@@ -25,7 +25,7 @@ class DefaultSseMessageEndpointValidatorTests {
2525 private final DefaultSseMessageEndpointValidator validator = new DefaultSseMessageEndpointValidator ();
2626
2727 @ ParameterizedTest
28- @ ValueSource (strings = { "/messages" , "messages?session=abc" , "/" })
28+ @ ValueSource (strings = { "/messages" , "messages?session=abc" , "/" , "https://mcp.example.com/messages" })
2929 void valid (String endpoint ) {
3030 assertThatCode (() -> validator .validate (SSE_URI , endpoint )).doesNotThrowAnyException ();
3131 }
@@ -41,32 +41,33 @@ void invalidEmpty(String endpoint) {
4141 @ ParameterizedTest
4242 @ ValueSource (strings = { "/foo/../bar" , "/foo/./bar" , "../bar" , "./bar" , "/foo/%2E%2E/bar" , "/foo/%2e/bar" })
4343 void invalidPathTraversal (String endpoint ) {
44- assertThatThrownBy (() -> validator .validate (SSE_URI , endpoint )).hasMessageContaining ("path-traversal" )
44+ assertThatThrownBy (() -> validator .validate (SSE_URI , endpoint ))
45+ .hasMessageContaining ("must not contain path-traversal segments" )
4546 .asInstanceOf (type (InvalidSseMessageEndpointException .class ))
4647 .extracting (InvalidSseMessageEndpointException ::getMessageEndpoint )
4748 .isEqualTo (endpoint );
4849 }
4950
5051 @ ParameterizedTest
51- @ ValueSource (strings = { "https://mcp.example.com/messages" , "https://127.0.0.1/messages" ,
52- "https://mcp.example.com:8443/messages" , "http://localhost:1234/messages" , "file:///etc/passwd" ,
53- "gopher://mcp.example.com/_test" })
52+ @ ValueSource (strings = { "https://127.0.0.1/messages" , "https://mcp.example.com:8443/messages" ,
53+ "http://localhost:1234/messages" , "file:///etc/passwd" , "gopher://mcp.example.com/_test" })
5454 void invalidAbsoluteUris (String endpoint ) {
55- // Even an absolute URI on the same origin must be rejected: the contract
56- // is that the messageEndpoint is a path-only relative reference.
57- assertThatThrownBy (() -> validator . validate ( SSE_URI , endpoint )). hasMessageContaining ("must be a relative path" )
55+ // Absolute URIs must be same-origin.
56+ assertThatThrownBy (() -> validator . validate ( SSE_URI , endpoint ))
57+ . hasMessageContaining ("must be a relative path or a same-origin URI " )
5858 .asInstanceOf (type (InvalidSseMessageEndpointException .class ))
5959 .extracting (InvalidSseMessageEndpointException ::getMessageEndpoint )
6060 .isEqualTo (endpoint );
6161
6262 }
6363
6464 @ ParameterizedTest
65- @ ValueSource (strings = { "//example/messages" , "//user:secret@example/messages" })
65+ @ ValueSource (strings = { "//example/messages" , "//user:secret@example/messages" , "//mcp.example.com/messages" })
6666 void invalidNetworkReference (String endpoint ) {
6767 // `//host/...` introduces an authority and is therefore not a pure path.
68+ // It is missing a scheme, so it fails same-origin check.
6869 assertThatThrownBy (() -> validator .validate (SSE_URI , endpoint ))
69- .hasMessageContaining ("must not contain an authority " )
70+ .hasMessageContaining ("must be a relative path or a same-origin URI " )
7071 .asInstanceOf (type (InvalidSseMessageEndpointException .class ))
7172 .extracting (InvalidSseMessageEndpointException ::getMessageEndpoint )
7273 .isEqualTo (endpoint );
0 commit comments