본문 바로가기
java

springboot Invalid 'expires' attribute

by 후린트 2023. 10. 10.
반응형

SpringBoot 로그에 아래와 같은 warning 메시지가 기록됐다.

Invalid cookie header: "Set-Cookie: .......... Expires=Thu, 12 Oct 2023 08:20:39 GMT; Path=/". 
Invalid 'expires' attribute: Thu, 12 Oct 2023 08:20:39 GMT

테스트 해보니 SpringBoot에서 RestTemplate으로 API호출을 하고 있는데 api호출할때마다 위의 로그가 출력되고 있다.

RestTemplate에 ConnectionPool 적용을 위해 HttpClient를 이용하여 HttpComponentsClientHttpRequestFactory 설정을 추가했다.

public static ClientHttpRequestFactory createRequestFactory(){
	PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
	HttpClientBuilder builder = HttpClients.custom().setConnectionManager(connectionManager);
	HttpClient httpClient = builder.build();
	HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient) {
		@Override
		protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
			HttpClientContext context = new HttpClientContext();
			context.setAttribute("http.protocol.expect-continue", false);
			return context;
		}
	};
}

 

API서버에서 전달받은 쿠키를 생성하면서 에러를 발생시키는 코드는 아래와 같다
Expires의 값을 Date로 parsing하려는데 지정된 datepattern과 맞지 않아서 exception이 발생한다.

httpclient-4.5.10.jar

BasicExpiresHandler.java

@Override
public void parse(final SetCookie cookie, final String value)
        throws MalformedCookieException {
    Args.notNull(cookie, "Cookie");
    if (value == null) {
        throw new MalformedCookieException("Missing value for 'expires' attribute");
    }
    final Date expiry = DateUtils.parseDate(value, this.datepatterns);
    if (expiry == null) {
        throw new MalformedCookieException("Invalid 'expires' attribute: "
                + value);
    }
    cookie.setExpiryDate(expiry);
}

BasicExpreiHandler를 선언하는 곳을 보면  datePattern이 다르다.
입력값 : Thu, 12 Oct 2023 08:20:39 GMT
datePattern : EEE, dd-MMM-yy HH:mm:ss z
패턴은 dash로 날짜 값들을 구분했는데 입력된 값은 뛰어쓰기로 구분했기에 exception이 발생한다.

DefaultCookieSpecProvider.java
 @Override
    public CookieSpec create(final HttpContext context) {
        if (cookieSpec == null) {
				...
                ...
				/* NetscapeDraftSpec.EXPIRES_PATTERN = "EEE, dd-MMM-yy HH:mm:ss z"; */
                 new BasicExpiresHandler(this.datepatterns != null ? this.datepatterns.clone() :
                                    new String[]{NetscapeDraftSpec.EXPIRES_PATTERN}));
                    this.cookieSpec = new DefaultCookieSpec(strict, obsoleteStrict, netscapeDraft);
                }
            }
        }
        return this.cookieSpec;
    }

 

RequestConfig에 cookieSpec을 정의하지 않았으므로 쿠키 스펙이 CookieSpecs.Default로 적용됐다.
Default일 경우에는 datePattern이 한개로 정의되어 에러가 발생하므로 
쿠키 스펙을 CookieSpecs.IGNORE_COOKIES로 정의하거나 또는 CookieSpecs.STANDARD로 정의한다.

	PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
RequestConfig requestConfig = RequestConfig.custom()
        .setCookieSpec(CookieSpecs.STANDARD) /* STANDARD */
/*      .setCookieSpec(CookieSpecs.IGNORE_COOKIES) */ /* IGNORE_COOKIES*/
        .build();
HttpClientBuilder builder = HttpClients.custom().setDefaultRequestConfig(requestConfig).setConnectionManager(connectionManager);
HttpClient httpClient = builder.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);

 

반응형