-
-
Notifications
You must be signed in to change notification settings - Fork 497
Validate HTTP response codes across the extractor #1322
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
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,10 +2,13 @@ | |
|
|
||
| import javax.annotation.Nonnull; | ||
| import javax.annotation.Nullable; | ||
| import java.util.Arrays; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| import org.schabi.newpipe.extractor.exceptions.HttpResponseException; | ||
|
|
||
| /** | ||
| * A Data class used to hold the results from requests made by the Downloader implementation. | ||
| */ | ||
|
|
@@ -30,6 +33,29 @@ public Response(final int responseCode, | |
| this.latestUrl = latestUrl; | ||
| } | ||
|
|
||
| // CHECKSTYLE:OFF | ||
| /** | ||
| * Validates the response codes for the given {@link Response}, and throws | ||
| * a {@link HttpResponseException} if the code is invalid | ||
| * @param response The response to validate | ||
| * @param validResponseCodes Expected valid response codes | ||
| * @throws HttpResponseException Thrown when the response code is not in {@code validResponseCodes}, | ||
| * or when {@code validResponseCodes} is empty and the code is a 4xx or 5xx error. | ||
| */ | ||
| // CHECKSTYLE:ON | ||
| public static void validateResponseCode(final Response response, | ||
| final int... validResponseCodes) | ||
| throws HttpResponseException { | ||
| final int code = response.responseCode(); | ||
| final var throwError = (validResponseCodes == null || validResponseCodes.length == 0) | ||
| ? code >= 400 && code <= 599 | ||
| : Arrays.stream(validResponseCodes).noneMatch(c -> c == code); | ||
|
|
||
| if (throwError) { | ||
| throw new HttpResponseException(response); | ||
| } | ||
| } | ||
|
|
||
| public int responseCode() { | ||
| return responseCode; | ||
| } | ||
|
|
@@ -80,4 +106,22 @@ public String getHeader(final String name) { | |
|
|
||
| return null; | ||
| } | ||
|
|
||
| // CHECKSTYLE:OFF | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why checkstyle off? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIRC, checkstyle was complaining about line being too long in the comment below, so I had to disable it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really important, but why don't you make the lines shorter then? Here you don't have long URLs There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do |
||
| /** | ||
| * Helper function simply to make it easier to validate response code inline | ||
| * before getting the code/body/latestUrl/etc. | ||
| * Validates the response codes for the given {@link Response}, and throws a {@link HttpResponseException} if the code is invalid | ||
| * @see Response#validateResponseCode(Response, int...) | ||
| * @param validResponseCodes Expected valid response codes | ||
| * @return {@link this} response | ||
| * @throws HttpResponseException Thrown when the response code is not in {@code validResponseCodes}, | ||
| * or when {@code validResponseCodes} is empty and the code is a 4xx or 5xx error. | ||
| */ | ||
| // CHECKSTYLE:ON | ||
| public Response validateResponseCode(final int... validResponseCodes) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In order to support the needs of other services (like youtube), I'd add the following methods: public Response throwIfResponseCode(int errorCode, final Function<Response, HttpResponseException> errorSupplier);
public Response throwIfResponseCodeInRange(final int errorCodeMin, final int errorCodeMax, final Function<Response, HttpResponseException> errorSupplier);I'd also rename this method to Then e.g. for YouTube we'd be able to do: response
// "https://www.youtube.com" is the URL to solve the captcha
.throwIfResponseCode(429, r -> new ReCaptchaException(r, "https://www.youtube.com"))
.throwIfInvalidResponseCode()While in PeerTube response
.throwIfResponseCode(429, r -> new TooManyRequestsException(r))
.throwIfInvalidResponseCode()And we'd remove the What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this. However, I think
Reading the second, it is easier to understand that 200 and 201 are the valid response codes, but one could presume with the first that 200 and 201 are invalid response codes and it should throw if one of those are returned. Thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| throws HttpResponseException { | ||
| validateResponseCode(this, validResponseCodes); | ||
| return this; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package org.schabi.newpipe.extractor.exceptions; | ||
|
|
||
| import org.schabi.newpipe.extractor.downloader.Response; | ||
|
|
||
| public class HttpResponseException extends ExtractionException { | ||
| public HttpResponseException(final Response response) { | ||
| this("Error in HTTP Response for " + response.latestUrl() + "\n\t" | ||
| + response.responseCode() + " - " + response.responseMessage()); | ||
| } | ||
|
|
||
| public HttpResponseException(final String message) { | ||
| super(message); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not inline this directly within the non-static
Response::validateResponseCode? This is basically a method on theResponseclass since it takesResponseas the first argument, so you might as well make it non-static.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intention was to allow for
response.validateResponseCodeandvalidateResponseCode(response)depending on the format of the call site.But in hindsight, I now recall that in C# (my main language) there is
EnsureSuccessStatusCodewhich can be used on the response itself, rather than a separate method.So yeah I think you're right, validation can just be done inline like how you have mentioned in your other comment