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

Implement ServiceDownException for case GitHub's API is down #1813

Merged
merged 5 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
Expand Up @@ -3,12 +3,15 @@
import org.jetbrains.annotations.NotNull;
import org.kohsuke.github.connector.GitHubConnectorResponse;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
bitwiseman marked this conversation as resolved.
Show resolved Hide resolved

import javax.annotation.Nonnull;

import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;

// TODO: Auto-generated Javadoc
Expand Down Expand Up @@ -49,6 +52,10 @@ abstract class GitHubConnectorResponseErrorHandler {

/** The status http bad request or greater. */
static GitHubConnectorResponseErrorHandler STATUS_HTTP_BAD_REQUEST_OR_GREATER = new GitHubConnectorResponseErrorHandler() {
private static final String CONTENT_TYPE = "Content-type";
private static final String TEXT_HTML = "text/html";
private static final String UNICORN_TITLE = "<title>Unicorn!";

@Override
public boolean isError(@NotNull GitHubConnectorResponse connectorResponse) throws IOException {
return connectorResponse.statusCode() >= HTTP_BAD_REQUEST;
Expand All @@ -58,9 +65,37 @@ public boolean isError(@NotNull GitHubConnectorResponse connectorResponse) throw
public void onError(@NotNull GitHubConnectorResponse connectorResponse) throws IOException {
if (connectorResponse.statusCode() == HTTP_NOT_FOUND) {
throw new FileNotFoundException(connectorResponse.request().url().toString());
} else if (isServiceDown(connectorResponse)) {
throw new ServiceDownException(connectorResponse);
} else {
throw new HttpException(connectorResponse);
}
}

private boolean isServiceDown(GitHubConnectorResponse connectorResponse) throws IOException {
if (connectorResponse.statusCode() < HTTP_INTERNAL_ERROR) {
return false;
}

String contentTypeHeader = connectorResponse.header(CONTENT_TYPE);
if (contentTypeHeader != null && contentTypeHeader.contains(TEXT_HTML)) {
BufferedReader bufReader = new BufferedReader(
new InputStreamReader(connectorResponse.bodyStream()));
bitwiseman marked this conversation as resolved.
Show resolved Hide resolved
String line;
int hardLineCap = 25;
// <title> node is expected in the beginning anyway.
// This way we do not load the raw long images' Strings, which are later in the HTML code
// Regex or .contains would result in iterating the whole HTML document, if it didn't match
// UNICORN_TITLE
while (hardLineCap > 0 && (line = bufReader.readLine()) != null) {
if (line.trim().startsWith(UNICORN_TITLE)) {
return true;
}
hardLineCap--;
}
}

return false;
}
};
}
19 changes: 19 additions & 0 deletions src/main/java/org/kohsuke/github/ServiceDownException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.kohsuke.github;

import org.kohsuke.github.connector.GitHubConnectorResponse;

import java.io.IOException;

/**
* Special {@link IOException} case for http exceptions, when {@link HttpException} is thrown due to GitHub service
* being down.
*
* Inherits from {@link HttpException} to maintain compatibility with existing clients.
*
* @author <a href="mailto:[email protected]">Rastislav Budinsky</a>
*/
public class ServiceDownException extends HttpException {
public ServiceDownException(GitHubConnectorResponse connectorResponse) {
bitwiseman marked this conversation as resolved.
Show resolved Hide resolved
super(connectorResponse);
}
}
16 changes: 16 additions & 0 deletions src/test/java/org/kohsuke/github/GitHubTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -397,4 +397,20 @@ public void testHeaderFieldName() throws Exception {
org.getResponseHeaderFields().keySet().contains("CacHe-ControL"));
assertThat(org.getResponseHeaderFields().get("cachE-cOntrol").get(0), is("private, max-age=60, s-maxage=60"));
}

/**
* Test expect GitHub {@link ServiceDownException}
*
*/
@Test
public void testCatchServiceDownException() {
snapshotNotAllowed();
try {
GHRepository repo = gitHub.getRepository("hub4j-test-org/github-api");
repo.getFileContent("ghcontent-ro/service-down");
fail("Exception was expected");
} catch (IOException e) {
assertThat(e.getClass().getName(), equalToIgnoringCase(ServiceDownException.class.getName()));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"login": "The-Huginn",
"id": 78657734,
"node_id": "MDQ6VXNlcjc4NjU3NzM0",
"avatar_url": "https://avatars.githubusercontent.com/u/78657734?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/The-Huginn",
"html_url": "https://github.com/The-Huginn",
"followers_url": "https://api.github.com/users/The-Huginn/followers",
"following_url": "https://api.github.com/users/The-Huginn/following{/other_user}",
"gists_url": "https://api.github.com/users/The-Huginn/gists{/gist_id}",
"starred_url": "https://api.github.com/users/The-Huginn/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/The-Huginn/subscriptions",
"organizations_url": "https://api.github.com/users/The-Huginn/orgs",
"repos_url": "https://api.github.com/users/The-Huginn/repos",
"events_url": "https://api.github.com/users/The-Huginn/events{/privacy}",
"received_events_url": "https://api.github.com/users/The-Huginn/received_events",
"type": "User",
"site_admin": false,
"name": "Rastislav Budinsky",
"company": "Red Hat",
"blog": "thehuginn.com",
"location": null,
"email": null,
"hireable": null,
"bio": null,
"twitter_username": "The_Hug1nn",
"public_repos": 47,
"public_gists": 0,
"followers": 3,
"following": 2,
"created_at": "2021-02-06T17:33:36Z",
"updated_at": "2024-03-11T08:56:45Z"
}
Loading
Loading