Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default ClientHttpRequestFactory provided by ClientHttpRequestFactories does not support HTTP Patch #41151

Closed
krezovic opened this issue Jun 18, 2024 · 1 comment
Labels
status: duplicate A duplicate of another issue

Comments

@krezovic
Copy link

krezovic commented Jun 18, 2024

As the title says, the org.springframework.boot.web.client.ClientHttpRequestFactories::get(ClientHttpRequestFactorySettings settings) falls back to org.springframework.http.client.SimpleClientHttpRequestFactory when no other optional dependency is present (apache hc5, jetty or okhttp), which uses java.net.HttpURLConnection underneath. However, java.net.HttpURLConnection does not and will never support HTTP Patch method as the original request was marked as "Won't Fix" and they delegate to new JDK11 Client API (which Spring Framework and Boot support).

https://bugs.openjdk.org/browse/JDK-7016595

Now, both RestTemplate and RestClient use the mentioned ClientHttpRequestFactories method and end up with SimpleClientHttpRequestFactory set as their request factory. Calling any HTTP endpoint with HTTP Method PATCH will throw an exception

org.opentest4j.AssertionFailedError: Unexpected exception thrown: org.springframework.web.client.ResourceAccessException: I/O error on PATCH request for "http://localhost:59537": Invalid HTTP method: PATCH

	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:152)
	at org.junit.jupiter.api.AssertDoesNotThrow.createAssertionFailedError(AssertDoesNotThrow.java:84)
	at org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:75)
	at org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:58)
	at org.junit.jupiter.api.Assertions.assertDoesNotThrow(Assertions.java:3228)
	at com.github.krezovic.resttemplate_bug.ResttemplateBugApplicationTests.rtTest(ResttemplateBugApplicationTests.java:30)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on PATCH request for "http://localhost:59537": Invalid HTTP method: PATCH
	at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.createResourceAccessException(DefaultRestClient.java:578)
	at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchangeInternal(DefaultRestClient.java:501)
	at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.retrieve(DefaultRestClient.java:463)
	at com.github.krezovic.resttemplate_bug.ResttemplateBugApplicationTests.lambda$rtTest$1(ResttemplateBugApplicationTests.java:30)
	at org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:71)
	... 6 more
Caused by: java.net.ProtocolException: Invalid HTTP method: PATCH
	at java.base/java.net.HttpURLConnection.setRequestMethod(HttpURLConnection.java:491)
	at java.base/sun.net.www.protocol.http.HttpURLConnection.setRequestMethod(HttpURLConnection.java:592)
	at org.springframework.http.client.SimpleClientHttpRequestFactory.prepareConnection(SimpleClientHttpRequestFactory.java:200)
	at org.springframework.http.client.SimpleClientHttpRequestFactory.createRequest(SimpleClientHttpRequestFactory.java:155)
	at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.createRequest(DefaultRestClient.java:557)
	at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchangeInternal(DefaultRestClient.java:483)

Reproducer located at https://github.com/krezovic/resttemplate-bug, simply run ./mvnw clean verify

The obvious fix would be to switch to JDK11 Client Factory which appears to be preferred by RestClient.Builder in org.springframework.web.client.DefaultRestClientBuilder::initRequestFactory but sadly is overriden by org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration to call the already mentioned method which does not consider JDK11 Client Factory at all.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 18, 2024
@philwebb
Copy link
Member

Thanks for raising the issue. This is not the first problem we've encountered with SimpleClientHttpRequestFactory, however changing the default is a little more involved that it would first appear. See the discussion in #36118 for more background.

I think we can consider this issue a duplicate of #36266. Until we have the configuration options in place, we can't consider switching to the JDK11 Client Factory since folks won't be able to switch back easily.

@philwebb philwebb closed this as not planned Won't fix, can't repro, duplicate, stale Jun 18, 2024
@philwebb philwebb added status: duplicate A duplicate of another issue and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

3 participants