Skip to content

Commit

Permalink
HttpUrlConnector extension (eclipse-ee4j#4613)
Browse files Browse the repository at this point in the history
* Created HttpUrlConnector extension for Http100Continue

Signed-off-by: Maxim Nesen <[email protected]>
  • Loading branch information
senivam authored and tvallin committed Nov 12, 2020
1 parent ec06918 commit dfe3772
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 23 deletions.
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));
}

}

0 comments on commit dfe3772

Please sign in to comment.