Skip to content

Commit a437a5d

Browse files
Add validation to all http calls in SoundcloudParsingHelper
1 parent ad9f4f4 commit a437a5d

1 file changed

Lines changed: 50 additions & 44 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudParsingHelper.java

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
66
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
77
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
8-
import static org.schabi.newpipe.extractor.downloader.Response.validateResponseCode;
98

109
import com.grack.nanojson.JsonArray;
1110
import com.grack.nanojson.JsonObject;
@@ -19,7 +18,6 @@
1918
import org.schabi.newpipe.extractor.NewPipe;
2019
import org.schabi.newpipe.extractor.channel.ChannelInfoItemsCollector;
2120
import org.schabi.newpipe.extractor.downloader.Downloader;
22-
import org.schabi.newpipe.extractor.downloader.Response;
2321
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
2422
import org.schabi.newpipe.extractor.exceptions.HttpResponseException;
2523
import org.schabi.newpipe.extractor.exceptions.ParsingException;
@@ -106,8 +104,9 @@ public static synchronized String clientId() throws ExtractionException, IOExcep
106104

107105
final Downloader dl = NewPipe.getDownloader();
108106

109-
final Response downloadResponse = dl.get("https://soundcloud.com").validateResponseCode();
110-
final String responseBody = downloadResponse.responseBody();
107+
final String responseBody = dl.get("https://soundcloud.com")
108+
.ensureSuccessResponseCode()
109+
.responseBody();
111110
final String clientIdPattern = ",client_id:\"(.*?)\"";
112111

113112
final Document doc = Jsoup.parse(responseBody);
@@ -123,7 +122,7 @@ public static synchronized String clientId() throws ExtractionException, IOExcep
123122
if (!isNullOrEmpty(srcUrl)) {
124123
try {
125124
clientId = Parser.matchGroup1(clientIdPattern, dl.get(srcUrl, headers)
126-
.validateResponseCode()
125+
.ensureSuccessResponseCode()
127126
.responseBody());
128127
return clientId;
129128
} catch (final RegexException ignored) {
@@ -155,7 +154,7 @@ public static DateWrapper parseDate(final String uploadDate) throws ParsingExcep
155154
/**
156155
* Call the endpoint "/resolve" of the API.
157156
* <p>
158-
* See https://web.archive.org/web/20170804051146/https://developers.soundcloud.com/docs/api/reference#resolve
157+
* See <a href="https://web.archive.org/web/20170804051146/https://developers.soundcloud.com/docs/api/reference#resolve">docs</a>
159158
*/
160159
// CHECKSTYLE:ON
161160
public static JsonObject resolveFor(@Nonnull final Downloader downloader, final String url)
@@ -166,7 +165,8 @@ public static JsonObject resolveFor(@Nonnull final Downloader downloader, final
166165

167166
try {
168167
final String response = downloader.get(apiUrl, SoundCloud.getLocalization())
169-
.responseBody();
168+
.ensureSuccessResponseCode()
169+
.responseBody();
170170
return JsonParser.object().from(response);
171171
} catch (final JsonParserException e) {
172172
throw new ParsingException("Could not parse json response", e);
@@ -184,7 +184,7 @@ public static String resolveUrlWithEmbedPlayer(final String apiUrl) throws IOExc
184184

185185
final var response = NewPipe.getDownloader().get("https://w.soundcloud.com/player/?url="
186186
+ Utils.encodeUrlUtf8(apiUrl), SoundCloud.getLocalization());
187-
validateResponseCode(response);
187+
response.ensureSuccessResponseCode();
188188
final var responseBody = response.responseBody();
189189
return Jsoup.parse(responseBody).select("link[rel=\"canonical\"]").first()
190190
.attr("abs:href");
@@ -195,7 +195,6 @@ public static String resolveUrlWithEmbedPlayer(final String apiUrl) throws IOExc
195195
*
196196
* @return the resolved id
197197
*/
198-
// TODO: what makes this method different from the others? Don' they all return the same?
199198
public static String resolveIdWithWidgetApi(final String urlString) throws IOException,
200199
ParsingException {
201200
String fixedUrl = urlString;
@@ -204,7 +203,14 @@ public static String resolveIdWithWidgetApi(final String urlString) throws IOExc
204203

205204
if (ON_URL_PATTERN.matcher(fixedUrl).find()) {
206205
try {
207-
fixedUrl = NewPipe.getDownloader().head(fixedUrl).latestUrl();
206+
fixedUrl = NewPipe.getDownloader()
207+
.head(fixedUrl)
208+
.throwIfServerError()
209+
.latestUrl();
210+
// Soundcloud returns HTTP 403 but it still redirects,
211+
// so can get the redirected url via latestUrl regardless.
212+
// This why only throw for 5xx and not 4xx.
213+
208214
// remove tracking params which are in the query string
209215
fixedUrl = fixedUrl.split("\\?")[0];
210216
} catch (final ExtractionException e) {
@@ -232,10 +238,11 @@ public static String resolveIdWithWidgetApi(final String urlString) throws IOExc
232238
+ Utils.encodeUrlUtf8(url.toString())
233239
+ "&format=json&client_id=" + SoundcloudParsingHelper.clientId();
234240

235-
final var response = NewPipe.getDownloader().get(widgetUrl,
236-
SoundCloud.getLocalization());
241+
final var responseBody = NewPipe.getDownloader()
242+
.get(widgetUrl, SoundCloud.getLocalization())
243+
.ensureSuccessResponseCode()
244+
.responseBody();
237245

238-
final var responseBody = response.validateResponseCode().responseBody();
239246
final JsonObject o = JsonParser.object().from(responseBody);
240247
return String.valueOf(JsonUtils.getValue(o, "id"));
241248
} catch (final JsonParserException e) {
@@ -249,16 +256,16 @@ public static String resolveIdWithWidgetApi(final String urlString) throws IOExc
249256
/**
250257
* Fetch the users from the given API and commit each of them to the collector.
251258
* <p>
252-
* This differ from {@link #getUsersFromApi(ChannelInfoItemsCollector, String)} in the sense
259+
* This differs from {@link #getUsersFromApi(ChannelInfoItemsCollector, String)} in the sense
253260
* that they will always get MIN_ITEMS or more.
254261
*
255-
* @param minItems the method will return only when it have extracted that many items
262+
* @param minItems the method will return only when it has extracted this many items
256263
* (equal or more)
257264
*/
258265
public static String getUsersFromApiMinItems(final int minItems,
259266
final ChannelInfoItemsCollector collector,
260267
final String apiUrl) throws IOException,
261-
ReCaptchaException, ParsingException {
268+
ReCaptchaException, ParsingException, HttpResponseException {
262269
String nextPageUrl = SoundcloudParsingHelper.getUsersFromApi(collector, apiUrl);
263270

264271
while (!nextPageUrl.isEmpty() && collector.getItems().size() < minItems) {
@@ -271,14 +278,16 @@ public static String getUsersFromApiMinItems(final int minItems,
271278
/**
272279
* Fetch the user items from the given API and commit each of them to the collector.
273280
*
274-
* @return the next streams url, empty if don't have
281+
* @return the next stream's url, empty if don't have
275282
*/
276283
@Nonnull
277284
public static String getUsersFromApi(final ChannelInfoItemsCollector collector,
278-
final String apiUrl) throws IOException,
279-
ReCaptchaException, ParsingException {
280-
final String response = NewPipe.getDownloader().get(apiUrl, SoundCloud.getLocalization())
281-
.responseBody();
285+
final String apiUrl)
286+
throws IOException, ReCaptchaException, ParsingException, HttpResponseException {
287+
final String response = NewPipe.getDownloader()
288+
.get(apiUrl, SoundCloud.getLocalization())
289+
.ensureSuccessResponseCode()
290+
.responseBody();
282291
final JsonObject responseObject;
283292

284293
try {
@@ -301,16 +310,16 @@ public static String getUsersFromApi(final ChannelInfoItemsCollector collector,
301310
/**
302311
* Fetch the streams from the given API and commit each of them to the collector.
303312
* <p>
304-
* This differ from {@link #getStreamsFromApi(StreamInfoItemsCollector, String)} in the sense
313+
* This differs from {@link #getStreamsFromApi(StreamInfoItemsCollector, String)} in the sense
305314
* that they will always get MIN_ITEMS or more items.
306315
*
307-
* @param minItems the method will return only when it have extracted that many items
316+
* @param minItems the method will return only when it has extracted this many items
308317
* (equal or more)
309318
*/
310319
public static String getStreamsFromApiMinItems(final int minItems,
311320
final StreamInfoItemsCollector collector,
312-
final String apiUrl) throws IOException,
313-
ReCaptchaException, ParsingException {
321+
final String apiUrl)
322+
throws IOException, ReCaptchaException, ParsingException, HttpResponseException {
314323
String nextPageUrl = SoundcloudParsingHelper.getStreamsFromApi(collector, apiUrl);
315324

316325
while (!nextPageUrl.isEmpty() && collector.getItems().size() < minItems) {
@@ -328,18 +337,16 @@ public static String getStreamsFromApiMinItems(final int minItems,
328337
@Nonnull
329338
public static String getStreamsFromApi(final StreamInfoItemsCollector collector,
330339
final String apiUrl,
331-
final boolean charts) throws IOException,
332-
ReCaptchaException, ParsingException {
333-
final Response response = NewPipe.getDownloader().get(apiUrl, SoundCloud
334-
.getLocalization());
335-
if (response.responseCode() >= 400) {
336-
throw new IOException("Could not get streams from API, HTTP " + response
337-
.responseCode());
338-
}
340+
final boolean charts)
341+
throws IOException, ReCaptchaException, ParsingException, HttpResponseException {
342+
final String responseBody = NewPipe.getDownloader()
343+
.get(apiUrl, SoundCloud.getLocalization())
344+
.ensureResponseCodeIsNotError()
345+
.responseBody();
339346

340347
final JsonObject responseObject;
341348
try {
342-
responseObject = JsonParser.object().from(response.responseBody());
349+
responseObject = JsonParser.object().from(responseBody);
343350
} catch (final JsonParserException e) {
344351
throw new ParsingException("Could not parse json response", e);
345352
}
@@ -370,23 +377,22 @@ private static String getNextPageUrl(@Nonnull final JsonObject response) {
370377
}
371378

372379
public static String getStreamsFromApi(final StreamInfoItemsCollector collector,
373-
final String apiUrl) throws ReCaptchaException,
374-
ParsingException, IOException {
380+
final String apiUrl)
381+
throws ReCaptchaException, ParsingException, IOException, HttpResponseException {
375382
return getStreamsFromApi(collector, apiUrl, false);
376383
}
377384

378385
public static String getInfoItemsFromApi(final MultiInfoItemsCollector collector,
379-
final String apiUrl) throws ReCaptchaException,
380-
ParsingException, IOException {
381-
final Response response = NewPipe.getDownloader().get(apiUrl, SoundCloud.getLocalization());
382-
if (response.responseCode() >= 400) {
383-
throw new IOException("Could not get streams from API, HTTP "
384-
+ response.responseCode());
385-
}
386+
final String apiUrl)
387+
throws ReCaptchaException, ParsingException, IOException, HttpResponseException {
388+
final String responseBody = NewPipe.getDownloader()
389+
.get(apiUrl, SoundCloud.getLocalization())
390+
.ensureResponseCodeIsNotError()
391+
.responseBody();
386392

387393
final JsonObject responseObject;
388394
try {
389-
responseObject = JsonParser.object().from(response.responseBody());
395+
responseObject = JsonParser.object().from(responseBody);
390396
} catch (final JsonParserException e) {
391397
throw new ParsingException("Could not parse json response", e);
392398
}

0 commit comments

Comments
 (0)