Skip to content

Commit 066af55

Browse files
committed
Implement OkHttpConnector using GitHubConnector
1 parent dbd481e commit 066af55

File tree

14 files changed

+268
-163
lines changed

14 files changed

+268
-163
lines changed

src/main/java/org/kohsuke/github/AbuseLimitHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ public abstract class AbuseLimitHandler {
3535
void onError(GitHubResponse.ResponseInfo responseInfo) throws IOException {
3636
GHIOException e = new HttpException("Abuse limit violation",
3737
responseInfo.statusCode(),
38-
responseInfo.headerField("Status"),
39-
responseInfo.url().toString()).withResponseHeaderFields(responseInfo.headers());
38+
responseInfo.header("Status"),
39+
responseInfo.url().toString()).withResponseHeaderFields(responseInfo.allHeaders());
4040
onError(e, new GitHubResponseInfoHttpURLConnectionAdapter(responseInfo));
4141
}
4242

src/main/java/org/kohsuke/github/GHNotificationStream.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,15 +192,15 @@ GHThread fetch() {
192192
idx = threads.length - 1;
193193

194194
nextCheckTime = calcNextCheckTime(response);
195-
lastModified = response.headerField("Last-Modified");
195+
lastModified = response.header("Last-Modified");
196196
}
197197
} catch (IOException | InterruptedException e) {
198198
throw new RuntimeException(e);
199199
}
200200
}
201201

202202
private long calcNextCheckTime(GitHubResponse<GHThread[]> response) {
203-
String v = response.headerField("X-Poll-Interval");
203+
String v = response.header("X-Poll-Interval");
204204
if (v == null)
205205
v = "60";
206206
long seconds = Integer.parseInt(v);

src/main/java/org/kohsuke/github/GHObject.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public abstract class GHObject extends GitHubInteractiveObject {
4545
@JacksonInject
4646
protected void setResponseHeaderFields(@CheckForNull GitHubResponse.ResponseInfo responseInfo) {
4747
if (responseInfo != null) {
48-
responseHeaderFields = responseInfo.headers();
48+
responseHeaderFields = responseInfo.allHeaders();
4949
}
5050
}
5151

src/main/java/org/kohsuke/github/GHRateLimit.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ public Record(@JsonProperty(value = "limit", required = true) int limit,
449449
this.resetEpochSeconds = resetEpochSeconds;
450450
String updatedAt = null;
451451
if (responseInfo != null) {
452-
updatedAt = responseInfo.headerField("Date");
452+
updatedAt = responseInfo.header("Date");
453453
}
454454
this.resetDate = calculateResetDate(updatedAt);
455455
}

src/main/java/org/kohsuke/github/GitHubClient.java

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,6 @@ public <T> GitHubResponse<T> sendRequest(GitHubRequest request, @CheckForNull Gi
367367
try {
368368
logRequest(request);
369369
rateLimitChecker.checkRateLimit(this, request);
370-
resetRequest(request, retries);
371370
responseInfo = connector.send(request);
372371
noteRateLimit(responseInfo);
373372
detectOTPRequired(responseInfo);
@@ -405,7 +404,7 @@ private GitHubRequest prepareRequest(GitHubRequest request) throws IOException {
405404
GitHubRequest.Builder<?> builder = request.toBuilder();
406405
// if the authentication is needed but no credential is given, try it anyway (so that some calls
407406
// that do work with anonymous access in the reduced form should still work.)
408-
if (!request.headers().containsKey("Authorization")) {
407+
if (!request.allHeaders().containsKey("Authorization")) {
409408
String authorization = getEncodedAuthorization();
410409
if (authorization != null) {
411410
builder.setHeader("Authorization", authorization);
@@ -430,12 +429,6 @@ private GitHubRequest prepareRequest(GitHubRequest request) throws IOException {
430429
return builder.build();
431430
}
432431

433-
private void resetRequest(GitHubRequest request, int retries) throws IOException {
434-
if (retries != CONNECTION_ERROR_RETRIES && request.inBody()) {
435-
request.body().reset();
436-
}
437-
}
438-
439432
private void logRequest(@Nonnull final GitHubRequest request) {
440433
LOGGER.log(FINE,
441434
() -> "GitHub API request [" + (getLogin() == null ? "anonymous" : getLogin()) + "]: "
@@ -491,8 +484,8 @@ private static IOException interpretApiError(IOException e,
491484

492485
if (responseInfo != null) {
493486
statusCode = responseInfo.statusCode();
494-
message = responseInfo.headerField("Status");
495-
headers = responseInfo.headers();
487+
message = responseInfo.header("Status");
488+
headers = responseInfo.allHeaders();
496489
errorMessage = responseInfo.errorMessage();
497490
}
498491

@@ -514,12 +507,12 @@ private static IOException interpretApiError(IOException e,
514507

515508
protected static boolean isRateLimitResponse(@Nonnull GitHubResponse.ResponseInfo responseInfo) {
516509
return responseInfo.statusCode() == HttpURLConnection.HTTP_FORBIDDEN
517-
&& "0".equals(responseInfo.headerField("X-RateLimit-Remaining"));
510+
&& "0".equals(responseInfo.header("X-RateLimit-Remaining"));
518511
}
519512

520513
protected static boolean isAbuseLimitResponse(@Nonnull GitHubResponse.ResponseInfo responseInfo) {
521514
return responseInfo.statusCode() == HttpURLConnection.HTTP_FORBIDDEN
522-
&& responseInfo.headerField("Retry-After") != null;
515+
&& responseInfo.header("Retry-After") != null;
523516
}
524517

525518
private static boolean retryConnectionError(IOException e, URL url, int retries) throws IOException {
@@ -552,8 +545,8 @@ private static boolean isInvalidCached404Response(GitHubResponse.ResponseInfo re
552545
// their 404 responses, this will result in at worst two requests being made for each 404
553546
// responses. However, only the second request will count against rate limit.
554547
if (responseInfo.statusCode() == 404 && Objects.equals(responseInfo.request().method(), "GET")
555-
&& responseInfo.headerField("ETag") != null
556-
&& !Objects.equals(responseInfo.request().headers().get("Cache-Control"), "no-cache")) {
548+
&& responseInfo.header("ETag") != null
549+
&& !Objects.equals(responseInfo.request().header("Cache-Control"), "no-cache")) {
557550
LOGGER.log(FINE,
558551
"Encountered GitHub invalid cached 404 from " + responseInfo.url()
559552
+ ". Retrying with \"Cache-Control\"=\"no-cache\"...");
@@ -564,11 +557,11 @@ private static boolean isInvalidCached404Response(GitHubResponse.ResponseInfo re
564557

565558
private void noteRateLimit(@Nonnull GitHubResponse.ResponseInfo responseInfo) {
566559
try {
567-
String limitString = Objects.requireNonNull(responseInfo.headerField("X-RateLimit-Limit"),
560+
String limitString = Objects.requireNonNull(responseInfo.header("X-RateLimit-Limit"),
568561
"Missing X-RateLimit-Limit");
569-
String remainingString = Objects.requireNonNull(responseInfo.headerField("X-RateLimit-Remaining"),
562+
String remainingString = Objects.requireNonNull(responseInfo.header("X-RateLimit-Remaining"),
570563
"Missing X-RateLimit-Remaining");
571-
String resetString = Objects.requireNonNull(responseInfo.headerField("X-RateLimit-Reset"),
564+
String resetString = Objects.requireNonNull(responseInfo.header("X-RateLimit-Reset"),
572565
"Missing X-RateLimit-Reset");
573566
int limit, remaining;
574567
long reset;
@@ -587,8 +580,8 @@ private static void detectOTPRequired(@Nonnull GitHubResponse.ResponseInfo respo
587580
if (responseInfo.statusCode() == HTTP_UNAUTHORIZED) {
588581
// In the case of a user with 2fa enabled, a header with X-GitHub-OTP
589582
// will be returned indicating the user needs to respond with an otp
590-
if (responseInfo.headerField("X-GitHub-OTP") != null) {
591-
throw new GHOTPRequiredException().withResponseHeaderFields(responseInfo.headers());
583+
if (responseInfo.header("X-GitHub-OTP") != null) {
584+
throw new GHOTPRequiredException().withResponseHeaderFields(responseInfo.allHeaders());
592585
}
593586
}
594587
}
@@ -642,7 +635,7 @@ void check(String apiUrl) throws IOException {
642635
private boolean isPrivateModeEnabled() {
643636
try {
644637
GitHubResponse<?> response = sendRequest(GitHubRequest.newBuilder().withApiUrl(getApiUrl()), null);
645-
return response.statusCode() == HTTP_UNAUTHORIZED && response.headerField("X-GitHub-Media-Type") != null;
638+
return response.statusCode() == HTTP_UNAUTHORIZED && response.header("X-GitHub-Media-Type") != null;
646639
} catch (IOException e) {
647640
return false;
648641
}

src/main/java/org/kohsuke/github/GitHubConnectorHttpConnectorAdapter.java

Lines changed: 61 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public HttpURLConnection connect(URL url) throws IOException {
6262
public GitHubResponse.ResponseInfo send(GitHubRequest request) throws IOException {
6363
HttpURLConnection connection;
6464
try {
65-
connection = HttpURLConnectionResponseInfo.setupConnection(httpConnector, request);
65+
connection = setupConnection(httpConnector, request);
6666
} catch (IOException e) {
6767
// An error in here should be wrapped to bypass http exception wrapping.
6868
throw new GHIOException(e.getMessage(), e);
@@ -76,6 +76,63 @@ public GitHubResponse.ResponseInfo send(GitHubRequest request) throws IOExceptio
7676
return new HttpURLConnectionResponseInfo(request, statusCode, headers, connection);
7777
}
7878

79+
@Nonnull
80+
static HttpURLConnection setupConnection(@Nonnull HttpConnector connector, @Nonnull GitHubRequest request)
81+
throws IOException {
82+
HttpURLConnection connection = connector.connect(request.url());
83+
setRequestMethod(request.method(), connection);
84+
buildRequest(request, connection);
85+
86+
return connection;
87+
}
88+
89+
/**
90+
* Set up the request parameters or POST payload.
91+
*/
92+
private static void buildRequest(GitHubRequest request, HttpURLConnection connection) throws IOException {
93+
for (Map.Entry<String, List<String>> e : request.allHeaders().entrySet()) {
94+
List<String> v = e.getValue();
95+
if (v != null)
96+
connection.setRequestProperty(e.getKey(), String.join(", ", v));
97+
}
98+
99+
if (request.inBody()) {
100+
connection.setDoOutput(true);
101+
IOUtils.copyLarge(request.body(), connection.getOutputStream());
102+
}
103+
}
104+
105+
private static void setRequestMethod(String method, HttpURLConnection connection) throws IOException {
106+
try {
107+
connection.setRequestMethod(method);
108+
} catch (ProtocolException e) {
109+
// JDK only allows one of the fixed set of verbs. Try to override that
110+
try {
111+
Field $method = HttpURLConnection.class.getDeclaredField("method");
112+
$method.setAccessible(true);
113+
$method.set(connection, method);
114+
} catch (Exception x) {
115+
throw (IOException) new IOException("Failed to set the custom verb").initCause(x);
116+
}
117+
// sun.net.www.protocol.https.DelegatingHttpsURLConnection delegates to another HttpURLConnection
118+
try {
119+
Field $delegate = connection.getClass().getDeclaredField("delegate");
120+
$delegate.setAccessible(true);
121+
Object delegate = $delegate.get(connection);
122+
if (delegate instanceof HttpURLConnection) {
123+
HttpURLConnection nested = (HttpURLConnection) delegate;
124+
setRequestMethod(method, nested);
125+
}
126+
} catch (NoSuchFieldException x) {
127+
// no problem
128+
} catch (IllegalAccessException x) {
129+
throw (IOException) new IOException("Failed to set the custom verb").initCause(x);
130+
}
131+
}
132+
if (!connection.getRequestMethod().equals(method))
133+
throw new IllegalStateException("Failed to set the request method to " + method);
134+
}
135+
79136
/**
80137
* Initial response information supplied to a {@link GitHubResponse.BodyHandler} when a response is initially
81138
* received and before the body is processed.
@@ -95,80 +152,17 @@ static class HttpURLConnectionResponseInfo extends GitHubResponse.ResponseInfo {
95152
this.connection = connection;
96153
}
97154

98-
@Nonnull
99-
static HttpURLConnection setupConnection(@Nonnull HttpConnector connector, @Nonnull GitHubRequest request)
100-
throws IOException {
101-
HttpURLConnection connection = connector.connect(request.url());
102-
setRequestMethod(request.method(), connection);
103-
buildRequest(request, connection);
104-
105-
return connection;
106-
}
107-
108-
/**
109-
* Set up the request parameters or POST payload.
110-
*/
111-
private static void buildRequest(GitHubRequest request, HttpURLConnection connection) throws IOException {
112-
for (Map.Entry<String, String> e : request.headers().entrySet()) {
113-
String v = e.getValue();
114-
if (v != null)
115-
connection.setRequestProperty(e.getKey(), v);
116-
}
117-
118-
if (request.inBody()) {
119-
connection.setDoOutput(true);
120-
try (InputStream body = request.body()) {
121-
byte[] bytes = new byte[32768];
122-
int read;
123-
while ((read = body.read(bytes)) != -1) {
124-
connection.getOutputStream().write(bytes, 0, read);
125-
}
126-
}
127-
}
128-
}
129-
130-
private static void setRequestMethod(String method, HttpURLConnection connection) throws IOException {
131-
try {
132-
connection.setRequestMethod(method);
133-
} catch (ProtocolException e) {
134-
// JDK only allows one of the fixed set of verbs. Try to override that
135-
try {
136-
Field $method = HttpURLConnection.class.getDeclaredField("method");
137-
$method.setAccessible(true);
138-
$method.set(connection, method);
139-
} catch (Exception x) {
140-
throw (IOException) new IOException("Failed to set the custom verb").initCause(x);
141-
}
142-
// sun.net.www.protocol.https.DelegatingHttpsURLConnection delegates to another HttpURLConnection
143-
try {
144-
Field $delegate = connection.getClass().getDeclaredField("delegate");
145-
$delegate.setAccessible(true);
146-
Object delegate = $delegate.get(connection);
147-
if (delegate instanceof HttpURLConnection) {
148-
HttpURLConnection nested = (HttpURLConnection) delegate;
149-
setRequestMethod(method, nested);
150-
}
151-
} catch (NoSuchFieldException x) {
152-
// no problem
153-
} catch (IllegalAccessException x) {
154-
throw (IOException) new IOException("Failed to set the custom verb").initCause(x);
155-
}
156-
}
157-
if (!connection.getRequestMethod().equals(method))
158-
throw new IllegalStateException("Failed to set the request method to " + method);
159-
}
160-
161155
/**
162156
* {@inheritDoc}
163157
*/
164-
InputStream bodyStream() throws IOException {
158+
public InputStream bodyStream() throws IOException {
165159
return wrapStream(connection.getInputStream());
166160
}
167161

168162
/**
169163
* {@inheritDoc}
170164
*/
171-
String errorMessage() {
165+
public String errorMessage() {
172166
String result = null;
173167
InputStream stream = null;
174168
try {
@@ -192,7 +186,7 @@ String errorMessage() {
192186
*
193187
*/
194188
private InputStream wrapStream(InputStream stream) throws IOException {
195-
String encoding = headerField("Content-Encoding");
189+
String encoding = header("Content-Encoding");
196190
if (encoding == null || stream == null)
197191
return stream;
198192
if (encoding.equals("gzip"))

src/main/java/org/kohsuke/github/GitHubPageIterator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ private void fetch() {
157157
*/
158158
private GitHubRequest findNextURL(GitHubResponse<T> nextResponse) throws MalformedURLException {
159159
GitHubRequest result = null;
160-
String link = nextResponse.headerField("Link");
160+
String link = nextResponse.header("Link");
161161
if (link != null) {
162162
for (String token : link.split(", ")) {
163163
if (token.endsWith("rel=\"next\"")) {

0 commit comments

Comments
 (0)