Add Remote Address to WebGraphQlRequest

This commit makes available the client remote address to various GraphQL
request implementations.

Closes gh-945
This commit is contained in:
Brian Clozel
2024-04-15 15:37:05 +02:00
parent 31f50752d8
commit d27580f6b3
10 changed files with 100 additions and 46 deletions

View File

@@ -78,7 +78,7 @@ final class WebGraphQlHandlerGraphQlTransport extends AbstractDirectGraphQlTrans
protected Mono<ExecutionGraphQlResponse> executeInternal(ExecutionGraphQlRequest executionRequest) {
WebGraphQlRequest request = new WebGraphQlRequest(
this.url, this.headers, null, Collections.emptyMap(), executionRequest,
this.url, this.headers, null, null, Collections.emptyMap(), executionRequest,
idGenerator.generateId().toString(), null);
return this.graphQlHandler.handleRequest(request).cast(ExecutionGraphQlResponse.class);

View File

@@ -16,6 +16,7 @@
package org.springframework.graphql.server;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.Collections;
import java.util.Locale;
@@ -58,8 +59,51 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements
private final MultiValueMap<String, HttpCookie> cookies;
@Nullable
private final InetSocketAddress remoteAddress;
private final Map<String, Object> attributes;
/**
* Create an instance.
* @param uri the URL for the HTTP request or WebSocket handshake
* @param headers the HTTP request headers
* @param cookies the HTTP request cookies
* @param remoteAddress the HTTP client remote address
* @param attributes request attributes
* @param body the deserialized content of the GraphQL request
* @param id an identifier for the GraphQL request
* @param locale the locale from the HTTP request, if any
* @since 1.3.0
*/
public WebGraphQlRequest(URI uri, HttpHeaders headers, @Nullable MultiValueMap<String, HttpCookie> cookies,
@Nullable InetSocketAddress remoteAddress, Map<String, Object> attributes,
GraphQlRequest body, String id, @Nullable Locale locale) {
this(uri, headers, cookies, remoteAddress, attributes, body.getDocument(),
body.getOperationName(), body.getVariables(), body.getExtensions(), id, locale);
}
/**
* Variant of {@link #WebGraphQlRequest(URI, HttpHeaders, MultiValueMap, Map, GraphQlRequest, String, Locale)}
* with a Map for the request body.
* @param uri the URL for the HTTP request or WebSocket handshake
* @param headers the HTTP request headers
* @param cookies the HTTP request cookies
* @param remoteAddress the HTTP client remote address
* @param attributes request attributes
* @param body the deserialized content of the GraphQL request
* @param id an identifier for the GraphQL request
* @param locale the locale from the HTTP request, if any
* @since 1.3.0
*/
public WebGraphQlRequest(
URI uri, HttpHeaders headers, @Nullable MultiValueMap<String, HttpCookie> cookies,
@Nullable InetSocketAddress remoteAddress, Map<String, Object> attributes,
Map<String, Object> body, String id, @Nullable Locale locale) {
this(uri, headers, cookies, remoteAddress, attributes, getQuery(body), getOperation(body),
getMap(VARIABLES_KEY, body), getMap(EXTENSIONS_KEY, body), id, locale);
}
/**
* Create an instance.
@@ -71,12 +115,14 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements
* @param id an identifier for the GraphQL request
* @param locale the locale from the HTTP request, if any
* @since 1.2.5
* @deprecated since 1.3.0 in favor {@link #WebGraphQlRequest(URI, HttpHeaders, MultiValueMap, InetSocketAddress, Map, Map, String, Locale)}
*/
@Deprecated(since = "1.3.0", forRemoval = true)
public WebGraphQlRequest(
URI uri, HttpHeaders headers, @Nullable MultiValueMap<String, HttpCookie> cookies,
Map<String, Object> attributes, GraphQlRequest body, String id, @Nullable Locale locale) {
this(uri, headers, cookies, attributes, body.getDocument(),
this(uri, headers, cookies, null, attributes, body.getDocument(),
body.getOperationName(), body.getVariables(), body.getExtensions(), id, locale);
}
@@ -91,12 +137,14 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements
* @param id an identifier for the GraphQL request
* @param locale the locale from the HTTP request, if any
* @since 1.1.3
* @deprecated since 1.3.0 in favor {@link #WebGraphQlRequest(URI, HttpHeaders, MultiValueMap, InetSocketAddress, Map, Map, String, Locale)}
*/
@Deprecated(since = "1.3.0", forRemoval = true)
public WebGraphQlRequest(
URI uri, HttpHeaders headers, @Nullable MultiValueMap<String, HttpCookie> cookies,
Map<String, Object> attributes, Map<String, Object> body, String id, @Nullable Locale locale) {
this(uri, headers, cookies, attributes, getQuery(body), getOperation(body),
this(uri, headers, cookies, null, attributes, getQuery(body), getOperation(body),
getMap(VARIABLES_KEY, body), getMap(EXTENSIONS_KEY, body), id, locale);
}
@@ -127,24 +175,10 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements
return (Map<String, Object>) value;
}
/**
* Create an instance.
* @param uri the URL for the HTTP request or WebSocket handshake
* @param headers the HTTP request headers
* @param body the deserialized content of the GraphQL request
* @param id an identifier for the GraphQL request
* @param locale the locale from the HTTP request, if any
* @deprecated as of 1.1.3 in favor of
* {@link #WebGraphQlRequest(URI, HttpHeaders, MultiValueMap, Map, GraphQlRequest, String, Locale)}
*/
@Deprecated(since = "1.1.3", forRemoval = true)
public WebGraphQlRequest(URI uri, HttpHeaders headers, Map<String, Object> body, String id, @Nullable Locale locale) {
this(uri, headers, null, Collections.emptyMap(), body, id, locale);
}
private WebGraphQlRequest(
URI uri, HttpHeaders headers, @Nullable MultiValueMap<String, HttpCookie> cookies,
Map<String, Object> attributes, String document, @Nullable String operationName,
@Nullable InetSocketAddress remoteAddress, Map<String, Object> attributes,
String document, @Nullable String operationName,
@Nullable Map<String, Object> variables, @Nullable Map<String, Object> extensions,
String id, @Nullable Locale locale) {
@@ -156,6 +190,7 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements
this.uri = UriComponentsBuilder.fromUri(uri).build(true);
this.headers = headers;
this.cookies = (cookies != null) ? CollectionUtils.unmodifiableMultiValueMap(cookies) : EMPTY_COOKIES;
this.remoteAddress = remoteAddress;
this.attributes = Collections.unmodifiableMap(attributes);
}
@@ -182,6 +217,15 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements
return this.cookies;
}
/**
* Return the remote address of the client, if available.
* @since 1.3.0
*/
@Nullable
public InetSocketAddress getRemoteAddress() {
return this.remoteAddress;
}
/**
* Return the request or WebSocket session attributes.
* @since 1.1.3

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 the original author or authors.
* Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,8 @@
package org.springframework.graphql.server;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
@@ -41,24 +41,6 @@ public class WebSocketGraphQlRequest extends WebGraphQlRequest {
private final WebSocketSessionInfo sessionInfo;
/**
* Create an instance.
* @param uri the URL for the HTTP request or WebSocket handshake
* @param headers the HTTP request headers
* @param body the deserialized content of the GraphQL request
* @param id the id from the GraphQL over WebSocket {@code "subscribe"} message
* @param locale the locale from the HTTP request, if any
* @param sessionInfo the WebSocket session id
* @deprecated as of 1.1.3 in favor of the constructor with cookies
*/
@Deprecated(since = "1.1.3", forRemoval = true)
public WebSocketGraphQlRequest(
URI uri, HttpHeaders headers, Map<String, Object> body, String id, @Nullable Locale locale,
WebSocketSessionInfo sessionInfo) {
this(uri, headers, null, Collections.emptyMap(), body, id, locale, sessionInfo);
}
/**
* Create an instance.
* @param uri the URL for the HTTP request or WebSocket handshake
@@ -70,13 +52,36 @@ public class WebSocketGraphQlRequest extends WebGraphQlRequest {
* @param locale the locale from the HTTP request, if any
* @param sessionInfo the WebSocket session id
* @since 1.1.3
* @deprecated in favor of {@link #WebSocketGraphQlRequest(URI, HttpHeaders, MultiValueMap, InetSocketAddress, Map, Map, String, Locale, WebSocketSessionInfo)}
*/
@Deprecated(since = "1.3.0", forRemoval = true)
public WebSocketGraphQlRequest(
URI uri, HttpHeaders headers, @Nullable MultiValueMap<String, HttpCookie> cookies,
Map<String, Object> attributes, Map<String, Object> body, String id, @Nullable Locale locale,
WebSocketSessionInfo sessionInfo) {
super(uri, headers, cookies, attributes, body, id, locale);
this(uri, headers, cookies, null, attributes, body, id, locale, sessionInfo);
}
/**
* Create an instance.
* @param uri the URL for the HTTP request or WebSocket handshake
* @param headers the HTTP request headers
* @param cookies the HTTP request cookies
* @param remoteAddress the client remote address
* @param attributes session attributes
* @param body the deserialized content of the GraphQL request
* @param id the id from the GraphQL over WebSocket {@code "subscribe"} message
* @param locale the locale from the HTTP request, if any
* @param sessionInfo the WebSocket session id
* @since 1.3.0
*/
public WebSocketGraphQlRequest(
URI uri, HttpHeaders headers, @Nullable MultiValueMap<String, HttpCookie> cookies,
@Nullable InetSocketAddress remoteAddress, Map<String, Object> attributes, Map<String, Object> body,
String id, @Nullable Locale locale, WebSocketSessionInfo sessionInfo) {
super(uri, headers, cookies, remoteAddress, attributes, body, id, locale);
Assert.notNull(sessionInfo, "WebSocketSessionInfo is required");
this.sessionInfo = sessionInfo;
}

View File

@@ -74,7 +74,8 @@ public class GraphQlHttpHandler extends AbstractGraphQlHttpHandler {
.flatMap((body) -> {
WebGraphQlRequest graphQlRequest = new WebGraphQlRequest(
serverRequest.uri(), serverRequest.headers().asHttpHeaders(),
serverRequest.cookies(), serverRequest.attributes(), body,
serverRequest.cookies(), serverRequest.remoteAddress().orElse(null),
serverRequest.attributes(), body,
serverRequest.exchange().getRequest().getId(),
serverRequest.exchange().getLocaleContext().getLocale());
if (logger.isDebugEnabled()) {

View File

@@ -70,7 +70,8 @@ public class GraphQlSseHandler extends AbstractGraphQlHttpHandler {
.flatMap((body) -> {
WebGraphQlRequest graphQlRequest = new WebGraphQlRequest(
serverRequest.uri(), serverRequest.headers().asHttpHeaders(),
serverRequest.cookies(), serverRequest.attributes(), body,
serverRequest.cookies(), serverRequest.remoteAddress().orElse(null),
serverRequest.attributes(), body,
serverRequest.exchange().getRequest().getId(),
serverRequest.exchange().getLocaleContext().getLocale());
if (logger.isDebugEnabled()) {

View File

@@ -172,7 +172,8 @@ public class GraphQlWebSocketHandler implements WebSocketHandler {
}
WebSocketGraphQlRequest request = new WebSocketGraphQlRequest(
handshakeInfo.getUri(), handshakeInfo.getHeaders(), handshakeInfo.getCookies(),
handshakeInfo.getAttributes(), payload, id, null, sessionInfo);
handshakeInfo.getRemoteAddress(), handshakeInfo.getAttributes(),
payload, id, null, sessionInfo);
if (logger.isDebugEnabled()) {
logger.debug("Executing: " + request);
}

View File

@@ -81,6 +81,7 @@ public class GraphQlHttpHandler extends AbstractGraphQlHttpHandler {
WebGraphQlRequest graphQlRequest = new WebGraphQlRequest(
serverRequest.uri(), serverRequest.headers().asHttpHeaders(), initCookies(serverRequest),
serverRequest.remoteAddress().orElse(null),
serverRequest.attributes(), readBody(serverRequest), this.idGenerator.generateId().toString(),
LocaleContextHolder.getLocale());

View File

@@ -69,7 +69,8 @@ public class GraphQlSseHandler extends AbstractGraphQlHttpHandler {
WebGraphQlRequest graphQlRequest = new WebGraphQlRequest(
serverRequest.uri(), serverRequest.headers().asHttpHeaders(), initCookies(serverRequest),
serverRequest.attributes(), readBody(serverRequest), this.idGenerator.generateId().toString(),
serverRequest.remoteAddress().orElse(null), serverRequest.attributes(),
readBody(serverRequest), this.idGenerator.generateId().toString(),
LocaleContextHolder.getLocale());
if (logger.isDebugEnabled()) {

View File

@@ -230,7 +230,7 @@ public class GraphQlWebSocketHandler extends TextWebSocketHandler implements Sub
Assert.notNull(uri, "Expected handshake url");
HttpHeaders headers = session.getHandshakeHeaders();
WebSocketGraphQlRequest request = new WebSocketGraphQlRequest(
uri, headers, null, session.getAttributes(), payload, id, null, state.getSessionInfo());
uri, headers, null, session.getRemoteAddress(), session.getAttributes(), payload, id, null, state.getSessionInfo());
if (logger.isDebugEnabled()) {
logger.debug("Executing: " + request);
}

View File

@@ -85,7 +85,7 @@ public class TestWebSocketSession implements WebSocketSession {
@Override
public InetSocketAddress getRemoteAddress() {
throw new UnsupportedOperationException();
return null;
}
@Override