Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions driver/src/main/java/oracle/nosql/driver/http/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import static oracle.nosql.driver.util.HttpConstants.REQUEST_ID_HEADER;
import static oracle.nosql.driver.util.HttpConstants.SERVER_SERIAL_VERSION;
import static oracle.nosql.driver.util.HttpConstants.SERVER_VERSION;
import static oracle.nosql.driver.util.HttpConstants.SERVER_WARNING;
import static oracle.nosql.driver.util.HttpConstants.USER_AGENT;
import static oracle.nosql.driver.util.HttpConstants.X_RATELIMIT_DELAY;
import static oracle.nosql.driver.util.LogUtil.isLoggable;
Expand Down Expand Up @@ -1270,6 +1271,8 @@ final Result processResponse(HttpResponseStatus status,
short serialVersionUsed,
short queryVersionUsed) {

processProxyWarning(headers);

if (!HttpResponseStatus.OK.equals(status)) {
processNotOKResponse(status, content);

Expand Down Expand Up @@ -1299,6 +1302,17 @@ final Result processResponse(HttpResponseStatus status,
return res;
}

/* Log a proxy-supplied warning once for each distinct message. */
void processProxyWarning(HttpHeaders headers) {
if (headers == null) {
return;
}
String warning = headers.get(SERVER_WARNING);
if (warning != null && !warning.isEmpty()) {
oneTimeMessage(warning);
}
}

/**
* Process an OK response
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ public class HttpConstants {
*/
public static final String SERVER_VERSION = "x-nosql-version";

/**
* A message supplied by the proxy for the driver to log as a warning.
* The driver logs each distinct message only once per handle.
*/
public static final String SERVER_WARNING = "x-nosql-warning";

/**
* Headers possibly set by the load balancer service to indicate original
* IP address
Expand Down
121 changes: 121 additions & 0 deletions driver/src/test/java/oracle/nosql/driver/http/ClientWarningTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*-
* Copyright (c) 2011, 2026 Oracle and/or its affiliates. All rights reserved.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* https://oss.oracle.com/licenses/upl/
*/

package oracle.nosql.driver.http;

import static oracle.nosql.driver.util.HttpConstants.SERVER_WARNING;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import org.junit.Test;

import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.ssl.SslContext;
import oracle.nosql.driver.AuthorizationProvider;
import oracle.nosql.driver.NoSQLException;
import oracle.nosql.driver.NoSQLHandleConfig;
import oracle.nosql.driver.httpclient.HttpClient;
import oracle.nosql.driver.ops.Request;

public class ClientWarningTest {

@Test
public void proxyWarningIsLoggedOncePerMessage() {
Logger logger = Logger.getLogger(getClass().getName());
logger.setUseParentHandlers(false);
logger.setLevel(Level.ALL);
CapturingHandler handler = new CapturingHandler();
logger.addHandler(handler);

Client client = new TestClient(logger, config());
try {
DefaultHttpHeaders headers = new DefaultHttpHeaders();
headers.add(SERVER_WARNING, "Upgrade the SDK");
processResponse(client, headers);
processResponse(client, headers);

headers.set(SERVER_WARNING, "A different proxy warning");
processResponse(client, headers);

assertEquals(2, handler.messages.size());
assertEquals("Upgrade the SDK", handler.messages.get(0));
assertEquals("A different proxy warning", handler.messages.get(1));
} finally {
client.shutdown();
logger.removeHandler(handler);
}
}

private void processResponse(Client client, DefaultHttpHeaders headers) {
assertThrows(NoSQLException.class,
() -> client.processResponse(
HttpResponseStatus.INTERNAL_SERVER_ERROR,
headers, Unpooled.EMPTY_BUFFER, null,
(short) 0, (short) 0));
}

private NoSQLHandleConfig config() {
NoSQLHandleConfig config =
new NoSQLHandleConfig("http://localhost:8080");
config.setAuthorizationProvider(new AuthorizationProvider() {
@Override
public String getAuthorizationString(Request request) {
return "test";
}

@Override
public void close() {
}
});
return config;
}

private static class TestClient extends Client {
TestClient(Logger logger, NoSQLHandleConfig config) {
super(logger, config);
}

@Override
public HttpClient createHttpClient(URL url,
NoSQLHandleConfig config,
SslContext sslCtx,
Logger logger) {
return new HttpClient(url.getHost(), url.getPort(), 1,
-1, 0, 0, 0, null, 0,
"ClientWarningTest", logger);
}
}

private static class CapturingHandler extends Handler {
private final List<String> messages = new ArrayList<>();

@Override
public void publish(LogRecord record) {
if (record.getLevel() == Level.WARNING) {
messages.add(record.getMessage());
}
}

@Override
public void flush() {
}

@Override
public void close() {
}
}
}