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

HttpUrlConnector extension #4613

Merged
merged 3 commits into from
Oct 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 <T> type of connection to be extended/processed
* @param <E> type of exception which can be thrown while processing/handling exeption
*
* @since 2.33
*/
interface ConnectorExtension<T, E extends Exception> {

/**
* 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;

}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ public class HttpUrlConnector implements Connector {
private final boolean isRestrictedHeaderPropertySet;
private final LazyValue<SSLSocketFactory> sslSocketFactory;

private final ConnectorExtension<HttpURLConnection, IOException> connectorExtension
= new HttpUrlExpect100ContinueConnectorExtension();

/**
* Create new {@code HttpUrlConnector} instance.
*
Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<HttpURLConnection, IOException> {

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));
}

}