Affects: spring-web-5.2.6.RELEASE
Hello there
Having this particular issue with this spring versions
worun@rn-aosd-d00-lapp01:/Local/AS/Sentinel/packages/NemoDataSetsService-21-2-0-20200720-224046-4/lib$ ls -alt | grep spring-web -rw-r--r--. 1 worun worun 1436459 Jun 25 21:20 spring-web-5.2.6.RELEASE.jar -rw-r--r--. 1 worun worun 954967 Jun 25 21:20 spring-webmvc-5.2.6.RELEASE.jar
org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Header Folding at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:79) at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:122) at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:102) at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63) at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:778) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:736) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:637) at com.apple.store.datasets.service.spring.proxy.DataSetsAuthoringServiceSpringAPIProxy.meta(DataSetsAuthoringServiceSpringAPIProxy.java:601)
400 Header Folding
Any idea what could be wrong?
This is the snippet of code:
@Secured({ "datasets:view" })
@RequestMapping(value = "dataSet/v1/{site}/{type}/{versionKey}/meta.json", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
@ResponseBody
public ResponseEntity<Map<String, Object>> meta(@PathVariable String site, @PathVariable String type,
@PathVariable String versionKey, HttpServletRequest request, Principal principal) {
try {
String uriString = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String servicebaseURL = null;
TypeProxy typeProxy = dataSetsAPIProxyConfiguration.getProxyConfiguration().get(site + "/" + type);
if (typeProxy != null) {
servicebaseURL = typeProxy.getAuthoringProxy().getBaseURL();
}
if (servicebaseURL == null) {
throw new IllegalArgumentException("No proxy endpoints configured for Site/Type " + site + "/" + type);
}
URI uri = new URI(servicebaseURL + "/" + uriString);
// HttpHeaders headers = new HttpHeaders();
/*
* headers.add("content-type", "application/json");
* dataSetsHeadersUtil.updateHttpHeaders(headers); transferAudit(principal,
* headers);
*/
RequestEntity<Map<String, Object>> requestEntity = new RequestEntity<Map<String, Object>>(HttpMethod.GET, uri);
ResponseEntity<DataTypeDefinition> dataTypeDefinitionResponse = dataSetsRestTemplate.exchange(requestEntity, DataTypeDefinition.class);
if (dataTypeDefinitionResponse.getStatusCode() == HttpStatus.OK) {
Map<String, Object> response = new HashMap<String, Object>();
ObjectMapper objectMapper = new ObjectMapper();
TypeReference<Map<String, Object>> typeReference = new TypeReference<Map<String, Object>>() {
};
response.put("status", "SUCCESS");
response.put("data", objectMapper.convertValue(dataTypeDefinitionResponse.getBody(), typeReference));
return new ResponseEntity<Map<String, Object>>(response, HttpStatus.OK);
} else {
return new ResponseEntity<Map<String, Object>>(HttpStatus.NOT_FOUND);
}
} catch (HttpClientErrorException httpClientErrorException) {
log.error("Critical error proxying keys call", httpClientErrorException);
return new ResponseEntity<Map<String, Object>>(httpClientErrorException.getStatusCode());
} catch (Exception exception) {
log.error("Critical error proxying keys call", exception);
return new ResponseEntity<Map<String, Object>>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Comment From: quaff
I guess your header value contains CRLF, please check dataSetsHeadersUtil.updateHttpHeaders(headers)
Comment From: maugomez77
@quaff that part is commented out btw
Comment From: maugomez77
also those values are in this form:
Header -> [content-type:"application/json", Authorization:"Bearer 4521c8567c55f21b7e61477d25ff6ec409439773c3718183357aace64b04cba86299a2dc116636efa5f6cc0369306bedb75d9149f38a03e7d057da578f2147d94649467123bdcd1b4c6b130fc00b234fee859542e82d1d03fd09da4f89187bc8f646833e24740c2d0870e0cb0eef3aa9680b9ddad30f81040b3cfbdd8395ec75b34b0269c37da45658b2380155eb0e71c6bb03412c7132d3e3043435b20a87543a2e6e9c13326850aab41aacdb8bcdef78aa4fa0c55b906ee2fed9e57d814b97c7a61df118b3c9cdcf938726f08dd56d970a68ea957f83a29f2e0638af35a2357fff71ed1c9f447758b5145ca88e1d7faa279ace76ddafdbb3169dab0332c4f3a06326abb70e78945e534ec52e5531236522e5ae1dde9039e9cac3bc13a17ad200fac1df2108280719c29b6b509f7a51bcef8a78d1071fcd723b84bb735494cf89a46521790827b6c2d8ccda171f4892f0148c150d0cde43abb941ec9543c42f389b215f7475a3415e102ff99acca753d2bdbbac2907c444cbbd18baf63a3d6308db9b1b8c1b2a4380b77c15a82f4422057ac3b8bbf5fd49cc0edb480c9e933c", X-DataSets-UserId:"joe_relentless", X-DataSets-UserEmail:"joe_relentless@gato.com"]
do you see any CRLF?
Comment From: quaff
@quaff that part is commented out btw
@maugomez77 Are you facing this error even comment out headers? maybe you are running the wrong version code, please double check.
Comment From: maugomez77
I already double check even in local @quaff
Not sure if also could be realted to the rest template being used there:
public class RestTemplatesUtils { private static Logger logger = LoggerFactory.getLogger(RestTemplatesUtils.class);
final public static int ConnectTimeout = 1000;
final public static int ReadTimeout = 30000;
public static RestTemplate getRestTemplate() {
// Obtain a connection factory based on whether we are enabling TLS going out
final HttpClientManager httpClientManager = HttpClientManager.getInstance();
final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClientManager.getClient());
// Prime timeouts on the factory and create a REST Template out of it
factory.setConnectTimeout(ConnectTimeout);
factory.setReadTimeout(ReadTimeout);
RestTemplate restTemplate = new RestTemplate(factory);
logger.info("RestTemplate initialized with TLS");
if (logger.isDebugEnabled()) {
logger.debug("RestTemplate initialized with TLS");
}
return restTemplate;
}
}
Comment From: quaff
It's possible default headers are added in HttpClientManager.getInstance()
via HttpClientBuilder::setDefaultHeaders
, I suggest you add a ClientHttpRequestInterceptor
to RestTemplate
then print all headers sent.
Comment From: maugomez77
The interesting thing is that if we called via browser a simple get:
https://rn-aosd-d00-lapp01.rno.apple.com:9999/8555/dataSet/v1/retail/family/datasettestv2/meta.json
port 9999 is a nginx port 8555 is a jetty application
is giving back:
Bad Message 400 reason: Header Folding
Comment From: quaff
The interesting thing is that if we called via browser a simple get:
https://rn-aosd-d00-lapp01.rno.apple.com:9999/8555/dataSet/v1/retail/family/datasettestv2/meta.json
port 9999 is a nginx port 8555 is a jetty application
is giving back:
Bad Message 400 reason: Header Folding
Then it's not an issue of spring, you should check jetty side.
Comment From: maugomez77
Issue was with one of headers in nginx:
https://github.com/eclipse/jetty.project/issues/5067
switch (_fieldState)
{
case FIELD:
switch (t.getType())
{
case COLON:
case SPACE:
case HTAB:
{
if (complianceViolation(HttpComplianceSection.NO_FIELD_FOLDING, _headerString))
throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Header Folding");
// header value without name - continuation?