0
votes

Client is sending encoded payload (percent encoded), while the given code works for a non encoded payload/XML (content-type:application/xml) it fails with a http 415 for encoded payload/XML file (Content-type: application/x-www-form-urlencoded).

I noticed that FormHttpMessageReader.java successfully decodes the payload (seen in the debug logs) but somewhere in the request flow after wards my code fails to map decoded XML correctly to the POJO.

Curl request -

curl -H 'Content-type: application/x-www-form-urlencoded' http://localhost:8081/api/v1/app/test  -d @encodedpyaload.xml -i-H 'Accept: application/xml, text/xml, application/x-www-form-urlencoded, */*’
HTTP/1.1 100 Continue

HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json
Content-Length: 158
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
Referrer-Policy: no-referrer

{"error":"415 UNSUPPORTED_MEDIA_TYPE \"Content type 'application/x-www-form-urlencoded' not supported for bodyType=test.package.Pojo\””}

Configuration class -

@Bean
public RouterFunction<ServerResponse> testRoute() {
    return route(POST(“/app/test”).and(contentType(MediaType.APPLICATION_FORM_URLENCODED)),
            handler::testHandler);
}

Handler Class

public Mono<ServerResponse> testHandler(final ServerRequest request) {

    return dataManager.testSave(request.bodyToMono(Pojo.class))
            .flatMap(uri -> ServerResponse.ok().build())
            .switchIfEmpty(ServerResponse.badRequest().build());
}

Updated Handler class code

Handler Class


return dataManager.testSave(request.bodyToMono(String.class)
        .flatMap(body -> Mono.just(URLDecoder.decode(body, StandardCharsets.UTF_8))
                .map(s -> createBody(s))).cast(Pojo.class))
        .flatMap(uri -> ServerResponse.ok().build())
        .switchIfEmpty(ServerResponse.badRequest().build());



private Pojo createBody(String s)  {
    XmlMapper mapper = new XmlMapper();
    Pojo pojo = new Pojo();
    try {
        pojo = mapper.readValue(s, Pojo.class);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return pojo;
}

POJO class

@XmlRootElement(name = “root”)
public class Pojo {

@XmlElement(name = “id”)
public long getId() {
    return id;
}

public void setId(long id) {
    this.id= id;
}

}
1
sending xml data that way is not a standard thats why there is no standard way for it. form-data is sent in a key:value format in the body so thats not going to work. My suggestion is either you try with a regular application/xml set as the content type. and use bodyToMono but i doubt that will work, or you process the body as a string and then convert the percent encoded data to standard encoding and parse the data. Why would you even send percentage encoded data as xml? why?Toerktumlare
It's xml data which is percent encoded and sent. In a simple servlet I would decode it as follows after reading the encoded InputStream from from the HttpServletRequest URLDecoder.decode(percentencodedstring, "UTF-8")Oten
i dint mean to offend you. The servlet reference is in the hope that someone could suggest a solution on those lines. I am working on your suggestion and trying to decode the data fetched from request.exchange.getRequest().getBody().Oten
do something in the lines of request.bodyToMono(String.class).flatMap(body -> Mono.just(URLDecoder.decode(body, "UTF-8")).map( // parse your decoded string )Toerktumlare
Added the updated code for Handler with my question above. Something is still wrong with the mapping to Pojo. dataManager.testSave() expects a Mono<Pojo>Oten

1 Answers

1
votes

There are 3 additional steps added here as we deviate away from processing a standard 'Content-type:application/xml'-

1) decode (percent encoded request body) the payload

2) Encode the decoded string to a XML

3) Convert the XML to Mono

Code changes:

handler function:

Like Thomas suggested -

request.bodyToMono(String.class).flatmap(body -> Mono.just(decode(body)).map(decodedstring -> createXML(decodedstring))).cast(Pojo.class))

and

private String decode(String body){
String str1 = "";
String str2 = body;

//if percent content is re-encoded multiple times
while(!str1.equals(str2)) {
str1=str2;
str2=URLDecoder.decode(str2,StandardCharsets.UTF_8)
}
return str2;
}

and

private Pojo createXML(String decodedstring) {
InputStream is = new ByteArrayInputStream(decodedstring.getBytes(Charset.forName("UTF-8")));
Pojo pojo = JAXB.unmarshal(is, Pojo.class);
return pojo;
}