handler) throws IOExcep
*
* Copies an input stream to an in-memory input stream. The performance on this is not great but
* {@link GitHubConnectorResponse#bodyStream()} is closed at the end of every call to
- * {@link GitHubClient#sendRequest(GitHubRequest, BodyHandler)}, so any reads to the original input stream must be
- * completed before then. There are a number of deprecated methods that return {@link InputStream}. This method
- * keeps all of them using the same code path.
+ * {@link GitHubClient#sendRequest(GitHubRequest, GitHubClient.BodyHandler)}, so any reads to the original input
+ * stream must be completed before then. There are a number of deprecated methods that return {@link InputStream}.
+ * This method keeps all of them using the same code path.
*
* @param inputStream
* the input stream to be copied
diff --git a/src/main/java/org/kohsuke/github/authorization/AnonymousAuthorizationProvider.java b/src/main/java/org/kohsuke/github/authorization/AnonymousAuthorizationProvider.java
new file mode 100644
index 0000000000..b71a42626a
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/authorization/AnonymousAuthorizationProvider.java
@@ -0,0 +1,15 @@
+package org.kohsuke.github.authorization;
+
+import java.io.IOException;
+
+/**
+ * A {@link AuthorizationProvider} that returns an empty authorization.
+ *
+ * This will result in the "Authorization" header not being added to a request.
+ */
+public class AnonymousAuthorizationProvider implements AuthorizationProvider {
+ @Override
+ public String getEncodedAuthorization() throws IOException {
+ return null;
+ }
+}
diff --git a/src/main/java/org/kohsuke/github/authorization/AuthorizationProvider.java b/src/main/java/org/kohsuke/github/authorization/AuthorizationProvider.java
index 4dd615885d..bc6ddc1931 100644
--- a/src/main/java/org/kohsuke/github/authorization/AuthorizationProvider.java
+++ b/src/main/java/org/kohsuke/github/authorization/AuthorizationProvider.java
@@ -3,12 +3,17 @@
import java.io.IOException;
/**
- * Provides a functional interface that returns a valid encodedAuthorization. This strategy allows for a provider that
- * dynamically changes the credentials. Each request will request the credentials from the provider.
+ * Provides a functional interface that returns a valid encodedAuthorization.
+ *
+ * This interface support the creation of providers based on immutable credentials or dynamic credentials which change
+ * of time. Each {@link org.kohsuke.github.connector.GitHubConnectorRequest} will call
+ * {@link #getEncodedAuthorization()} on the provider.
+ *
+ * @author Liam Newman
*/
public interface AuthorizationProvider {
/**
- * An static instance for an ANONYMOUS authorization provider
+ * A static instance for an ANONYMOUS authorization provider
*/
AuthorizationProvider ANONYMOUS = new AnonymousAuthorizationProvider();
@@ -27,17 +32,8 @@ public interface AuthorizationProvider {
*
* @return encoded authorization string, can be null
* @throws IOException
- * on any error that prevents the provider from getting a valid authorization
+ * on any error that prevents the provider from returning a valid authorization
*/
String getEncodedAuthorization() throws IOException;
- /**
- * A {@link AuthorizationProvider} that ensures that no credentials are returned
- */
- class AnonymousAuthorizationProvider implements AuthorizationProvider {
- @Override
- public String getEncodedAuthorization() throws IOException {
- return null;
- }
- }
}
diff --git a/src/main/java/org/kohsuke/github/authorization/ImmutableAuthorizationProvider.java b/src/main/java/org/kohsuke/github/authorization/ImmutableAuthorizationProvider.java
index 41a113285a..20c780b9ba 100644
--- a/src/main/java/org/kohsuke/github/authorization/ImmutableAuthorizationProvider.java
+++ b/src/main/java/org/kohsuke/github/authorization/ImmutableAuthorizationProvider.java
@@ -7,7 +7,7 @@
import javax.annotation.CheckForNull;
/**
- * A {@link AuthorizationProvider} that always returns the same credentials
+ * An {@link AuthorizationProvider} that always returns the same credentials.
*/
public class ImmutableAuthorizationProvider implements AuthorizationProvider {
@@ -99,6 +99,8 @@ public String getEncodedAuthorization() {
/**
* An internal class representing all user-related credentials, which are credentials that have a login or should
* query the user endpoint for the login matching this credential.
+ *
+ * @see org.kohsuke.github.authorization.UserAuthorizationProvider UserAuthorizationProvider
*/
private static class UserProvider extends ImmutableAuthorizationProvider implements UserAuthorizationProvider {
diff --git a/src/main/java/org/kohsuke/github/authorization/OrgAppInstallationAuthorizationProvider.java b/src/main/java/org/kohsuke/github/authorization/OrgAppInstallationAuthorizationProvider.java
index 31af483eb9..d2437d3afb 100644
--- a/src/main/java/org/kohsuke/github/authorization/OrgAppInstallationAuthorizationProvider.java
+++ b/src/main/java/org/kohsuke/github/authorization/OrgAppInstallationAuthorizationProvider.java
@@ -13,7 +13,7 @@
import javax.annotation.Nonnull;
/**
- * Provides an AuthorizationProvider that performs automatic token refresh.
+ * An AuthorizationProvider that performs automatic token refresh for an organization's AppInstallation.
*/
public class OrgAppInstallationAuthorizationProvider extends GitHub.DependentAuthorizationProvider {
diff --git a/src/main/java/org/kohsuke/github/connector/GitHubConnector.java b/src/main/java/org/kohsuke/github/connector/GitHubConnector.java
index cbff11dbc5..63ffe9892d 100644
--- a/src/main/java/org/kohsuke/github/connector/GitHubConnector.java
+++ b/src/main/java/org/kohsuke/github/connector/GitHubConnector.java
@@ -7,7 +7,7 @@
import java.io.IOException;
/**
- * Pluggability for customizing HTTP request behaviors or using altogether different library.
+ * Interface for customizing HTTP request behaviors or using any HTTP client library for interacting with GitHub.
*
* @author Liam Newman
*/
@@ -15,10 +15,11 @@
public interface GitHubConnector {
/**
+ * Sends a request and retrieves a raw response for processing.
*
* Implementers of {@link GitHubConnector#send(GitHubConnectorRequest)} process the information from a
- * {@link GitHubConnectorRequest} to open an HTTP connection and retrieve a response. They then return a class that
- * extends {@link GitHubConnectorResponse} for their response data.
+ * {@link GitHubConnectorRequest} to open an HTTP connection and retrieve a raw response. They then return a class
+ * that extends {@link GitHubConnectorResponse} corresponding their response data.
*
* Clients should not implement their own {@link GitHubConnectorRequest}. The {@link GitHubConnectorRequest}
* provided by the caller of {@link GitHubConnector#send(GitHubConnectorRequest)} should be passed to the
@@ -29,16 +30,18 @@ public interface GitHubConnector {
* @return a GitHubConnectorResponse for the request
* @throws IOException
* if there is an I/O error
+ *
+ * @author Liam Newman
*/
GitHubConnectorResponse send(GitHubConnectorRequest connectorRequest) throws IOException;
/**
* Default implementation used when connector is not set by user.
*
- * This calls {@link DefaultGitHubConnector#create} to get the default connector instance. The output of that method
- * may differ depending on Java version and system properties.
+ * This calls {@link DefaultGitHubConnector#create()} to get the default connector instance. The output of that
+ * method may differ depending on Java version and system properties.
*
- * @see DefaultGitHubConnector#create
+ * @see DefaultGitHubConnector#create() DefaultGitHubConnector#create()
*/
GitHubConnector DEFAULT = DefaultGitHubConnector.create();
diff --git a/src/main/java/org/kohsuke/github/connector/GitHubConnectorRequest.java b/src/main/java/org/kohsuke/github/connector/GitHubConnectorRequest.java
index 1b6e22f532..e00d59dcec 100644
--- a/src/main/java/org/kohsuke/github/connector/GitHubConnectorRequest.java
+++ b/src/main/java/org/kohsuke/github/connector/GitHubConnectorRequest.java
@@ -9,15 +9,17 @@
import javax.annotation.Nonnull;
/**
- * A request passed to {@link GitHubConnector#send(GitHubConnectorRequest)} to get a {@link GitHubConnectorResponse}.\
+ * A request passed to {@link GitHubConnector#send(GitHubConnectorRequest)} to get a {@link GitHubConnectorResponse}.
*
* Implementers of {@link GitHubConnector#send(GitHubConnectorRequest)} process the information from a
* {@link GitHubConnectorRequest} to open an HTTP connection and retrieve a response. They then return a class that
- * extends {@link GitHubConnectorResponse} for their response data.
+ * extends {@link GitHubConnectorResponse} corresponding their response data.
*
* Clients should not implement their own {@link GitHubConnectorRequest}. The {@link GitHubConnectorRequest} provided by
* the caller of {@link GitHubConnector#send(GitHubConnectorRequest)} should be passed to the constructor of
* {@link GitHubConnectorResponse}.
+ *
+ * @author Liam Newman
*/
public interface GitHubConnectorRequest {
diff --git a/src/main/java/org/kohsuke/github/connector/GitHubConnectorResponse.java b/src/main/java/org/kohsuke/github/connector/GitHubConnectorResponse.java
index 1790a183d3..3700236074 100644
--- a/src/main/java/org/kohsuke/github/connector/GitHubConnectorResponse.java
+++ b/src/main/java/org/kohsuke/github/connector/GitHubConnectorResponse.java
@@ -1,12 +1,15 @@
package org.kohsuke.github.connector;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.apache.commons.io.IOUtils;
+import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.*;
+import java.util.zip.GZIPInputStream;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -14,9 +17,13 @@
/**
* Response information supplied when a response is received and before the body is processed.
*
- * Instances of this class are closed once the response is done being processed. This means that contents of the body
- * stream will not be readable after a call is completed. Status code, response headers, and request details will still
- * be readable but it is recommended that consumers copy any information they need rather than retaining a reference.
+ * Instances of this class are closed once the response is done being processed. This means that {@link #bodyStream()}
+ * will not be readable after a call is completed.
+ *
+ * {@link #statusCode()}, {@link #allHeaders()}, and {@link #request()} will still be readable but it is recommended
+ * that consumers copy any information they need rather than retaining a reference to {@link GitHubConnectorResponse}.
+ *
+ * @author Liam Newman
*/
public abstract class GitHubConnectorResponse implements Closeable {
@@ -112,4 +119,78 @@ public int statusCode() {
public Map> allHeaders() {
return headers;
}
+
+ /**
+ * Handles the "Content-Encoding" header.
+ *
+ * @param stream
+ * the stream to possibly wrap
+ * @return an input stream potentially wrapped to decode gzip input
+ * @throws IOException
+ * if an I/O Exception occurs.
+ */
+ protected InputStream wrapStream(InputStream stream) throws IOException {
+ String encoding = header("Content-Encoding");
+ if (encoding == null || stream == null)
+ return stream;
+ if (encoding.equals("gzip"))
+ return new GZIPInputStream(stream);
+
+ throw new UnsupportedOperationException("Unexpected Content-Encoding: " + encoding);
+ }
+
+ public abstract static class ByteArrayResponse extends GitHubConnectorResponse {
+
+ private boolean inputStreamRead = false;
+ private byte[] inputBytes = null;
+ private boolean isClosed = false;
+
+ protected ByteArrayResponse(@Nonnull GitHubConnectorRequest request,
+ int statusCode,
+ @Nonnull Map> headers) {
+ super(request, statusCode, headers);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public InputStream bodyStream() throws IOException {
+ if (isClosed) {
+ throw new IOException("Response is closed");
+ }
+ synchronized (this) {
+ if (!inputStreamRead) {
+ InputStream rawStream = rawBodyStream();
+ try (InputStream stream = wrapStream(rawStream)) {
+ if (stream != null) {
+ inputBytes = IOUtils.toByteArray(stream);
+ }
+ }
+ inputStreamRead = true;
+ }
+ }
+
+ return inputBytes == null ? null : new ByteArrayInputStream(inputBytes);
+ }
+
+ /**
+ * Get the raw implementation specific body stream for this response.
+ *
+ * This method will only be called once to completion. If an exception is thrown, it may be called multiple
+ * times.
+ *
+ * @return the stream for the raw response
+ * @throws IOException
+ * if an I/O Exception occurs.
+ */
+ @CheckForNull
+ protected abstract InputStream rawBodyStream() throws IOException;
+
+ @Override
+ public void close() throws IOException {
+ isClosed = true;
+ this.inputBytes = null;
+ }
+ }
}
diff --git a/src/main/java/org/kohsuke/github/connector/GitHubConnectorResponseHttpUrlConnectionAdapter.java b/src/main/java/org/kohsuke/github/connector/GitHubConnectorResponseHttpUrlConnectionAdapter.java
index 4ae6b83cbe..30ae888b90 100644
--- a/src/main/java/org/kohsuke/github/connector/GitHubConnectorResponseHttpUrlConnectionAdapter.java
+++ b/src/main/java/org/kohsuke/github/connector/GitHubConnectorResponseHttpUrlConnectionAdapter.java
@@ -15,6 +15,8 @@
*
* Behavior is equivalent to a {@link HttpURLConnection} after {@link HttpURLConnection#connect()} has been called.
* Methods that make no sense throw {@link UnsupportedOperationException}.
+ *
+ * @author Liam Newman
*/
@Deprecated
class GitHubConnectorResponseHttpUrlConnectionAdapter extends HttpURLConnection {
@@ -27,16 +29,6 @@ public GitHubConnectorResponseHttpUrlConnectionAdapter(GitHubConnectorResponse c
this.connectorResponse = connectorResponse;
}
- /**
- * Readable to support {@link GitHubConnectorResponse#fromHttpURLConnectionAdapter(HttpURLConnection)} which only
- * exist for testing.
- *
- * @return
- */
- GitHubConnectorResponse connectorResponse() {
- return connectorResponse;
- }
-
@Override
public String getHeaderFieldKey(int n) {
List keys = new ArrayList<>(connectorResponse.allHeaders().keySet());
diff --git a/src/main/java/org/kohsuke/github/extras/HttpClientGitHubConnector.java b/src/main/java/org/kohsuke/github/extras/HttpClientGitHubConnector.java
index ea03c2319b..baa4365c8a 100644
--- a/src/main/java/org/kohsuke/github/extras/HttpClientGitHubConnector.java
+++ b/src/main/java/org/kohsuke/github/extras/HttpClientGitHubConnector.java
@@ -7,7 +7,7 @@
import java.io.IOException;
/**
- * {@link GitHubConnector} wrapper that sets timeout
+ * {@link GitHubConnector} for platforms that do not support Java 11 HttpClient.
*
* @author Liam Newman
*/
diff --git a/src/main/java/org/kohsuke/github/extras/okhttp3/OkHttpConnector.java b/src/main/java/org/kohsuke/github/extras/okhttp3/OkHttpConnector.java
index abcfd15bc0..bc09891ea2 100644
--- a/src/main/java/org/kohsuke/github/extras/okhttp3/OkHttpConnector.java
+++ b/src/main/java/org/kohsuke/github/extras/okhttp3/OkHttpConnector.java
@@ -19,8 +19,7 @@
* 304 response does not count against the rate limit. See http://developer.github.com/v3/#conditional-requests
*
* @author Liam Newman
- * @author Kohsuke Kawaguchi
- * @deprecated Use OkHttpGitHubConnector instead.
+ * @deprecated Use {@link OkHttpGitHubConnector} instead.
*/
@Deprecated
public class OkHttpConnector implements HttpConnector {
diff --git a/src/main/java/org/kohsuke/github/extras/okhttp3/OkHttpGitHubConnector.java b/src/main/java/org/kohsuke/github/extras/okhttp3/OkHttpGitHubConnector.java
index b83848906f..d61fde220b 100644
--- a/src/main/java/org/kohsuke/github/extras/okhttp3/OkHttpGitHubConnector.java
+++ b/src/main/java/org/kohsuke/github/extras/okhttp3/OkHttpGitHubConnector.java
@@ -7,25 +7,24 @@
import org.kohsuke.github.connector.GitHubConnectorRequest;
import org.kohsuke.github.connector.GitHubConnectorResponse;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import java.util.zip.GZIPInputStream;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
- * {@link HttpConnector} for {@link OkHttpClient}.
+ * {@link GitHubConnector} for {@link OkHttpClient}.
*
- * Unlike {@link #DEFAULT}, OkHttp does response caching. Making a conditional request against GitHubAPI and receiving a
- * 304 response does not count against the rate limit. See http://developer.github.com/v3/#conditional-requests
+ * Unlike {@link #DEFAULT}, OkHttp supports response caching. Making a conditional request against GitHub API and
+ * receiving a 304 response does not count against the rate limit. See
+ * http://developer.github.com/v3/#conditional-requests
*
* @author Liam Newman
- * @author Kohsuke Kawaguchi
*/
public class OkHttpGitHubConnector implements GitHubConnector {
private static final String HEADER_NAME = "Cache-Control";
@@ -105,10 +104,7 @@ private List TlsConnectionSpecs() {
*
* Implementation specific to {@link okhttp3.Response}.
*/
- private static class OkHttpGitHubConnectorResponse extends GitHubConnectorResponse {
-
- private boolean bodyBytesRead = false;
- private byte[] bodyBytes = null;
+ private static class OkHttpGitHubConnectorResponse extends GitHubConnectorResponse.ByteArrayResponse {
@Nonnull
private final Response response;
@@ -118,51 +114,20 @@ private static class OkHttpGitHubConnectorResponse extends GitHubConnectorRespon
this.response = response;
}
- /**
- * {@inheritDoc}
- */
+ @CheckForNull
@Override
- public InputStream bodyStream() throws IOException {
- readBodyBytes();
- InputStream stream = bodyBytes == null ? null : new ByteArrayInputStream(bodyBytes);
- return stream;
- }
-
- private void readBodyBytes() throws IOException {
- synchronized (this) {
- if (!bodyBytesRead) {
- try (ResponseBody body = response.body()) {
- if (body != null) {
- try (InputStream stream = wrapStream(body.byteStream())) {
- if (stream != null) {
- bodyBytes = IOUtils.toByteArray(stream);
- }
- }
- }
- }
- bodyBytesRead = true;
- }
+ protected InputStream rawBodyStream() throws IOException {
+ ResponseBody body = response.body();
+ if (body != null) {
+ return body.byteStream();
+ } else {
+ return null;
}
}
- /**
- * Handles the "Content-Encoding" header.
- *
- * @param stream
- * the stream to possibly wrap
- */
- private InputStream wrapStream(InputStream stream) throws IOException {
- String encoding = header("Content-Encoding");
- if (encoding == null || stream == null)
- return stream;
- if (encoding.equals("gzip"))
- return new GZIPInputStream(stream);
-
- throw new UnsupportedOperationException("Unexpected Content-Encoding: " + encoding);
- }
-
@Override
public void close() throws IOException {
+ super.close();
response.close();
}
}
diff --git a/src/main/java/org/kohsuke/github/function/BodyHandler.java b/src/main/java/org/kohsuke/github/function/BodyHandler.java
deleted file mode 100644
index 0083dcd526..0000000000
--- a/src/main/java/org/kohsuke/github/function/BodyHandler.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.kohsuke.github.function;
-
-import org.kohsuke.github.connector.GitHubConnectorResponse;
-
-import java.io.IOException;
-
-/**
- * Represents a supplier of results that can throw.
- *
- * @param
- * the type of results supplied by this supplier
- */
-@FunctionalInterface
-public interface BodyHandler extends FunctionThrows {
-}
diff --git a/src/main/java/org/kohsuke/github/internal/DefaultGitHubConnector.java b/src/main/java/org/kohsuke/github/internal/DefaultGitHubConnector.java
index 899294c2dd..1f7d488036 100644
--- a/src/main/java/org/kohsuke/github/internal/DefaultGitHubConnector.java
+++ b/src/main/java/org/kohsuke/github/internal/DefaultGitHubConnector.java
@@ -10,7 +10,9 @@
/**
* Internal class that selects what kind of {@link GitHubConnector} will be the default.
*
- * Allow behavior to be changed for different version of Java, such as supporting Java 11 HttpClient.
+ * Allows behavior to be changed for different versions of Java, such as supporting Java 11 HttpClient.
+ *
+ * @author Liam Newman
*/
public final class DefaultGitHubConnector {
diff --git a/src/main/java/org/kohsuke/github/internal/GitHubConnectorHttpConnectorAdapter.java b/src/main/java/org/kohsuke/github/internal/GitHubConnectorHttpConnectorAdapter.java
index b4a55dab1f..01417e08dd 100644
--- a/src/main/java/org/kohsuke/github/internal/GitHubConnectorHttpConnectorAdapter.java
+++ b/src/main/java/org/kohsuke/github/internal/GitHubConnectorHttpConnectorAdapter.java
@@ -7,7 +7,6 @@
import org.kohsuke.github.connector.GitHubConnectorRequest;
import org.kohsuke.github.connector.GitHubConnectorResponse;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
@@ -16,17 +15,16 @@
import java.net.URL;
import java.util.List;
import java.util.Map;
-import java.util.logging.Logger;
-import java.util.zip.GZIPInputStream;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
-import static java.util.logging.Level.*;
-
/**
* Adapts an HttpConnector to be usable as GitHubConnector.
*
* For internal use only.
+ *
+ * @author Liam Newman
*/
public final class GitHubConnectorHttpConnectorAdapter implements GitHubConnector, HttpConnector {
@@ -150,15 +148,13 @@ private static void setRequestMethod(String method, HttpURLConnection connection
}
/**
- * Initial response information supplied to a {@link org.kohsuke.github.function.BodyHandler} when a response is
- * initially received and before the body is processed.
+ * Initial response information supplied when a response is received but before the body is processed.
*
* Implementation specific to {@link HttpURLConnection}. For internal use only.
*/
- public final static class HttpURLConnectionGitHubConnectorResponse extends GitHubConnectorResponse {
-
- private boolean inputStreamRead = false;
- private byte[] inputBytes = null;
+ public final static class HttpURLConnectionGitHubConnectorResponse
+ extends
+ GitHubConnectorResponse.ByteArrayResponse {
@Nonnull
private final HttpURLConnection connection;
@@ -171,26 +167,14 @@ public final static class HttpURLConnectionGitHubConnectorResponse extends GitHu
this.connection = connection;
}
- /**
- * {@inheritDoc}
- */
- public InputStream bodyStream() throws IOException {
- synchronized (this) {
- if (!inputStreamRead) {
- InputStream rawStream = connection.getErrorStream();
- if (rawStream == null) {
- rawStream = connection.getInputStream();
- }
- try (InputStream stream = wrapStream(rawStream)) {
- if (stream != null) {
- inputBytes = IOUtils.toByteArray(stream);
- }
- }
- inputStreamRead = true;
- }
+ @CheckForNull
+ @Override
+ protected InputStream rawBodyStream() throws IOException {
+ InputStream rawStream = connection.getErrorStream();
+ if (rawStream == null) {
+ rawStream = connection.getInputStream();
}
-
- return inputBytes == null ? null : new ByteArrayInputStream(inputBytes);
+ return rawStream;
}
/**
@@ -205,28 +189,13 @@ public HttpURLConnection toHttpURLConnection() {
return connection;
}
- /**
- * Handles the "Content-Encoding" header.
- *
- * @param stream
- * the stream to possibly wrap
- *
- */
- private InputStream wrapStream(InputStream stream) throws IOException {
- String encoding = header("Content-Encoding");
- if (encoding == null || stream == null)
- return stream;
- if (encoding.equals("gzip"))
- return new GZIPInputStream(stream);
-
- throw new UnsupportedOperationException("Unexpected Content-Encoding: " + encoding);
- }
-
- private static final Logger LOGGER = Logger.getLogger(GitHub.class.getName());
-
@Override
public void close() throws IOException {
- IOUtils.closeQuietly(connection.getInputStream());
+ super.close();
+ try {
+ IOUtils.closeQuietly(connection.getInputStream());
+ } catch (IOException e) {
+ }
}
}
diff --git a/src/main/java11/org/kohsuke/github/extras/HttpClientGitHubConnector.java b/src/main/java11/org/kohsuke/github/extras/HttpClientGitHubConnector.java
index c8df48ca14..1e2a0cfce0 100644
--- a/src/main/java11/org/kohsuke/github/extras/HttpClientGitHubConnector.java
+++ b/src/main/java11/org/kohsuke/github/extras/HttpClientGitHubConnector.java
@@ -1,13 +1,10 @@
package org.kohsuke.github.extras;
+import org.apache.commons.io.IOUtils;
import org.kohsuke.github.connector.GitHubConnector;
import org.kohsuke.github.connector.GitHubConnectorRequest;
import org.kohsuke.github.connector.GitHubConnectorResponse;
-import org.apache.commons.io.IOUtils;
-
-import javax.annotation.Nonnull;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
@@ -17,10 +14,12 @@
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Map;
-import java.util.zip.GZIPInputStream;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
/**
- * {@link GitHubConnector} wrapper that sets timeout
+ * {@link GitHubConnector} for {@link HttpClient}.
*
* @author Liam Newman
*/
@@ -29,7 +28,7 @@ public class HttpClientGitHubConnector implements GitHubConnector {
private final HttpClient client;
/**
- * Instantiates a new HttpClientGitHubConnector.
+ * Instantiates a new HttpClientGitHubConnector with a defaut HttpClient.
*/
public HttpClientGitHubConnector() {
this(HttpClient.newHttpClient());
@@ -39,7 +38,7 @@ public HttpClientGitHubConnector() {
* Instantiates a new HttpClientGitHubConnector.
*
* @param client
- * the base
+ * the HttpClient to be used
*/
public HttpClientGitHubConnector(HttpClient client) {
this.client = client;
@@ -73,7 +72,7 @@ public GitHubConnectorResponse send(GitHubConnectorRequest connectorRequest) thr
HttpResponse httpResponse = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
return new HttpClientGitHubConnectorResponse(connectorRequest, httpResponse);
} catch (InterruptedException e) {
- throw (InterruptedIOException)new InterruptedIOException(e.getMessage()).initCause(e);
+ throw (InterruptedIOException) new InterruptedIOException(e.getMessage()).initCause(e);
}
}
@@ -82,61 +81,27 @@ public GitHubConnectorResponse send(GitHubConnectorRequest connectorRequest) thr
*
* Implementation specific to {@link HttpResponse}.
*/
- private static class HttpClientGitHubConnectorResponse extends GitHubConnectorResponse {
- private boolean bodyBytesRead = false;
- private byte[] bodyBytes = null;
+ private static class HttpClientGitHubConnectorResponse extends GitHubConnectorResponse.ByteArrayResponse {
@Nonnull
private final HttpResponse response;
- protected HttpClientGitHubConnectorResponse(@Nonnull GitHubConnectorRequest request, @Nonnull HttpResponse response) {
+ protected HttpClientGitHubConnectorResponse(@Nonnull GitHubConnectorRequest request,
+ @Nonnull HttpResponse response) {
super(request, response.statusCode(), response.headers().map());
this.response = response;
}
- /**
- * {@inheritDoc}
- */
+ @CheckForNull
@Override
- public InputStream bodyStream() throws IOException {
- readBodyBytes();
- InputStream stream = bodyBytes == null ? null : new ByteArrayInputStream(bodyBytes);
- return stream;
- }
-
- private void readBodyBytes() throws IOException {
- synchronized (this) {
- if (!bodyBytesRead) {
- try (InputStream stream = wrapStream(response.body())) {
- if (stream != null) {
- bodyBytes = IOUtils.toByteArray(stream);
- }
- }
- bodyBytesRead = true;
- }
- }
- }
-
- /**
- * Handles the "Content-Encoding" header.
- *
- * @param stream
- * the stream to possibly wrap
- *
- */
- private InputStream wrapStream(InputStream stream) throws IOException {
- String encoding = header("Content-Encoding");
- if (encoding == null || stream == null)
- return stream;
- if (encoding.equals("gzip"))
- return new GZIPInputStream(stream);
-
- throw new UnsupportedOperationException("Unexpected Content-Encoding: " + encoding);
+ protected InputStream rawBodyStream() throws IOException {
+ return response.body();
}
@Override
public void close() throws IOException {
- IOUtils.closeQuietly(response.body());
+ super.close();
+ IOUtils.closeQuietly(response.body());
}
}
}
diff --git a/src/test/java/org/kohsuke/github/AbuseLimitHandlerTest.java b/src/test/java/org/kohsuke/github/AbuseLimitHandlerTest.java
index d496cc9aea..bbd0751147 100644
--- a/src/test/java/org/kohsuke/github/AbuseLimitHandlerTest.java
+++ b/src/test/java/org/kohsuke/github/AbuseLimitHandlerTest.java
@@ -53,12 +53,13 @@ protected WireMockConfiguration getWireMockOptions() {
public void testHandler_Fail() throws Exception {
// Customized response that templates the date to keep things working
snapshotNotAllowed();
+ final HttpURLConnection[] savedConnection = new HttpURLConnection[1];
gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl())
.withAbuseLimitHandler(new AbuseLimitHandler() {
@Override
public void onError(IOException e, HttpURLConnection uc) throws IOException {
-
+ savedConnection[0] = uc;
// Verify
assertThat(uc.getDate(), Matchers.greaterThanOrEqualTo(new Date().getTime() - 10000));
assertThat(uc.getExpiration(), equalTo(0L));
@@ -103,7 +104,6 @@ public void onError(IOException e, HttpURLConnection uc) throws IOException {
assertThat(errorStream, notNullValue());
String errorString = IOUtils.toString(errorStream, StandardCharsets.UTF_8);
fail();
- assertThat(errorString, containsString("Must have push access to repository"));
} catch (IOException ex) {
assertThat(ex, notNullValue());
assertThat(ex.getMessage(), containsString("stream is closed"));
@@ -196,6 +196,11 @@ public void onError(IOException e, HttpURLConnection uc) throws IOException {
assertThat(e.getMessage(), equalTo("Abuse limit reached"));
}
+ if (savedConnection[0].toString().contains("GitHubConnectorResponseHttpUrlConnectionAdapter")) {
+ // error stream is non-null above. null here because response has been closed.
+ assertThat(savedConnection[0].getErrorStream(), nullValue());
+ }
+
assertThat(mockGitHub.getRequestCount(), equalTo(2));
}