diff --git a/core-client/src/main/java/org/glassfish/jersey/client/internal/ConnectorExtension.java b/core-client/src/main/java/org/glassfish/jersey/client/internal/ConnectorExtension.java new file mode 100644 index 0000000000..022cbc6b2e --- /dev/null +++ b/core-client/src/main/java/org/glassfish/jersey/client/internal/ConnectorExtension.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.client.internal; + +import org.glassfish.jersey.client.ClientRequest; + +/** + * Connector extension interface to extend existing connector's functionality. + * + * @param type of connection to be extended/processed + * @param type of exception which can be thrown while processing/handling exeption + * + * @since 2.33 + */ +interface ConnectorExtension { + + /** + * Main function which allows extension of connector's functionality + * + * @param request request instance to work with (shall contain all required settings/params to be used in extension) + * @param extensionParam connector's instance which is being extended + */ + void invoke(ClientRequest request, T extensionParam); + + /** + * After connection is done some additional work may be done + * + * @param extensionParam connector's instance which is being extended + */ + void postConnectionProcessing(T extensionParam); + + /** + * Exception handling method + * + * @param request request instance to work with (shall contain all required settings/params to be used in extension) + * @param ex exception instance which comes from connector + * @param extensionParam connector's instance which is being extended + * @return true if exception was handled by this method, false otherwise + * @throws E can thor exception if required by handling + */ + boolean handleException(ClientRequest request, T extensionParam, E ex) throws E; + +} \ No newline at end of file diff --git a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java index 0f0614c519..777ed407d0 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java @@ -102,6 +102,9 @@ public class HttpUrlConnector implements Connector { private final boolean isRestrictedHeaderPropertySet; private final LazyValue sslSocketFactory; + private final ConnectorExtension connectorExtension + = new HttpUrlExpect100ContinueConnectorExtension(); + /** * Create new {@code HttpUrlConnector} instance. * @@ -352,7 +355,7 @@ private ClientResponse _apply(final ClientRequest request) throws IOException { } } - processExpect100Continue(request, uc, length, entityProcessing); + processExtentions(request, uc); request.setStreamProvider(contentLength -> { setOutboundHeaders(request.getStringHeaders(), uc); @@ -364,11 +367,7 @@ private ClientResponse _apply(final ClientRequest request) throws IOException { setOutboundHeaders(request.getStringHeaders(), uc); } } catch (IOException ioe) { - if (uc.getResponseCode() == -1) { - throw ioe; - } else { - storedException = ioe; - } + storedException = handleException(request, ioe, uc); } final int code = uc.getResponseCode(); @@ -530,24 +529,19 @@ public Object run() throws NoSuchFieldException, } } - private static void processExpect100Continue(ClientRequest request, HttpURLConnection uc, - long length, RequestEntityProcessing entityProcessing) { - final Boolean expectContinueActivated = request.resolveProperty( - ClientProperties.EXPECT_100_CONTINUE, Boolean.class); - final Long expectContinueSizeThreshold = request.resolveProperty( - ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, - ClientProperties.DEFAULT_EXPECT_100_CONTINUE_THRESHOLD_SIZE); - - final boolean allowStreaming = length > expectContinueSizeThreshold - || entityProcessing == RequestEntityProcessing.CHUNKED; - - if (!Boolean.TRUE.equals(expectContinueActivated) - || !("POST".equals(uc.getRequestMethod()) || "PUT".equals(uc.getRequestMethod())) - || !allowStreaming - ) { - return; + private void processExtentions(ClientRequest request, HttpURLConnection uc) { + connectorExtension.invoke(request, uc); + } + + private IOException handleException(ClientRequest request, IOException ex, HttpURLConnection uc) throws IOException { + if (connectorExtension.handleException(request, uc, ex)) { + return null; + } + if (uc.getResponseCode() == -1) { + throw ex; + } else { + return ex; } - uc.setRequestProperty("Expect", "100-Continue"); } @Override diff --git a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlExpect100ContinueConnectorExtension.java b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlExpect100ContinueConnectorExtension.java new file mode 100644 index 0000000000..2e727eb9fa --- /dev/null +++ b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlExpect100ContinueConnectorExtension.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.client.internal; + +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.ClientRequest; +import org.glassfish.jersey.client.RequestEntityProcessing; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.ProtocolException; + +class HttpUrlExpect100ContinueConnectorExtension + implements ConnectorExtension { + + private static final String EXCEPTION_MESSAGE = "Server rejected operation"; + + @Override + public void invoke(ClientRequest request, HttpURLConnection uc) { + + final long length = request.getLengthLong(); + final RequestEntityProcessing entityProcessing = request.resolveProperty( + ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.class); + + final Boolean expectContinueActivated = request.resolveProperty( + ClientProperties.EXPECT_100_CONTINUE, Boolean.class); + final Long expectContinueSizeThreshold = request.resolveProperty( + ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, + ClientProperties.DEFAULT_EXPECT_100_CONTINUE_THRESHOLD_SIZE); + + final boolean allowStreaming = length > expectContinueSizeThreshold + || entityProcessing == RequestEntityProcessing.CHUNKED; + + if (!Boolean.TRUE.equals(expectContinueActivated) + || !("POST".equals(uc.getRequestMethod()) || "PUT".equals(uc.getRequestMethod())) + || !allowStreaming + ) { + return; + } + uc.setRequestProperty("Expect", "100-Continue"); + } + + @Override + public void postConnectionProcessing(HttpURLConnection extensionParam) { + //nothing here, we do not process post connection extension + } + + @Override + public boolean handleException(ClientRequest request, HttpURLConnection extensionParam, IOException ex) { + + final Boolean expectContinueActivated = request.resolveProperty( + ClientProperties.EXPECT_100_CONTINUE, Boolean.FALSE); + + return expectContinueActivated + && (ex instanceof ProtocolException && ex.getMessage().equals(EXCEPTION_MESSAGE)); + } + +} \ No newline at end of file