Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ private HttpConstants() {}

public static final int PRECONDITION_FAILED = 412;

public static final String ACCEPT = "Accept";

public static final String ACCEPT_ENCODING = "Accept-Encoding";

public static final String CACHE_CONTROL = "Cache-Control";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
import com.google.gson.JsonParseException;

public class RFC9457Parser {
private static Gson gson = new GsonBuilder()
private static final Gson GSON = new GsonBuilder()
.registerTypeAdapter(RFC9457Payload.class, new RFC9457PayloadAdapter())
.create();

public static RFC9457Payload parse(String data) {
return gson.fromJson(data, RFC9457Payload.class);
return GSON.fromJson(data, RFC9457Payload.class);
}

private static class RFC9457PayloadAdapter implements JsonDeserializer<RFC9457Payload> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,24 @@ public URI getInstance() {

@Override
public String toString() {
return "RFC9457Payload {" + "type="
+ type + ", status="
+ status + ", title='"
+ title + ", detail='"
+ detail + ", instance="
+ instance + '}';
StringBuilder builder = new StringBuilder();
builder.append("RFC9457Payload [");
if (type != null) {
builder.append("type=").append(type).append(", ");
}
if (status != null) {
builder.append("status=").append(status).append(", ");
}
if (title != null) {
builder.append("title=").append(title).append(", ");
}
if (detail != null) {
builder.append("detail=").append(detail).append(", ");
}
if (instance != null) {
builder.append("instance=").append(instance);
}
builder.append("]");
return builder.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,19 @@
* A reporter for RFC 9457 messages.
* RFC 9457 is a standard for reporting problems in HTTP responses as a JSON object.
* There are members specified in the RFC but none of those appear to be required,
* @see <a href=https://www.rfc-editor.org/rfc/rfc9457#section-3-7>rfc9457 section 3.7</a>
* see <a href=https://www.rfc-editor.org/rfc/rfc9457#section-3-7>rfc9457 section 3.7</a>
* Given the JSON fields are not mandatory, this reporter simply extracts the body of the
* response without validation.
* A RFC 9457 message is detected by the content type "application/problem+json".
* A RFC 9457 message is detected by the content type {@value #CONTENT_TYPE_PROBLEM_DETAILS_JSON} in the response header.
*
* @param <T> The type of the response.
* @param <E> The base exception type to throw if the response is not a RFC9457 message.
* @param <R> The type of the request or request builder (which allows to modify headers)
* @see <a href=https://www.rfc-editor.org/rfc/rfc9457#section-3-7>RFC 9457</a>
*/
public abstract class RFC9457Reporter<T, E extends Exception> {
public abstract class RFC9457Reporter<T, E extends Exception, R> {
public static final String CONTENT_TYPE_PROBLEM_DETAILS_JSON = "application/problem+json";

protected abstract boolean isRFC9457Message(T response);

protected abstract int getStatusCode(T response);
Expand All @@ -41,8 +45,24 @@ public abstract class RFC9457Reporter<T, E extends Exception> {

protected abstract String getBody(T response) throws IOException;

/**
* Prepares the request to accept RFC 9457 responses.
* This involves setting/updating the "Accept" header to include "application/problem+json".
* @param request The request or request builder to prepare
* @see <a href=https://www.rfc-editor.org/rfc/rfc9457#section-3-2>RFC 9457 section 3.2</a>
*/
public abstract void prepareRequest(R request);

protected boolean hasRFC9457ContentType(String contentType) {
return "application/problem+json".equals(contentType);
if (contentType == null) {
return false;
}
// strip off parameters
int idx = contentType.indexOf(';');
if (idx > -1) {
contentType = contentType.substring(0, idx);
}
return CONTENT_TYPE_PROBLEM_DETAILS_JSON.equals(contentType);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CF sends Content-Type: application/problem+json; charset=utf-8 on response, so equality will not work.

Copy link
Copy Markdown
Member

@cstamas cstamas Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just "contains" or "starts with"? (with proper nullcheck on contentType?). Just to keep it simple.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strip attributes from that header now in e4521fa.

}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.eclipse.aether.spi.connector.transport.http.RFC9457;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class RFC9457ReporterTest {

@Test
void hasRFC9457ContentType() {
RFC9457Reporter<Object, Exception, Object> reporter = new RFC9457Reporter<Object, Exception, Object>() {
@Override
protected boolean isRFC9457Message(Object response) {
return false;
}

@Override
protected int getStatusCode(Object response) {
return 0;
}

@Override
protected String getReasonPhrase(Object response) {
return null;
}

@Override
protected String getBody(Object response) {
return null;
}

@Override
public void prepareRequest(Object request) {}
};
assertTrue(reporter.hasRFC9457ContentType("application/problem+json"));
assertTrue(reporter.hasRFC9457ContentType("application/problem+json; charset=utf-8"));
}
}
Loading