Fix: Crash on HTML response in EventRepository and others
- Fixed: Value <! DOCTYPE cannot be converted to JSONArray in EventRepository - Fixed: Added HTML validation in UpdateManager and DeviceRegistry - Fixed: Improved HTTP error handling in StreamUrlResolver - Improved: Error messages in PlayerActivity - Bumped version to 9.4.3
This commit is contained in:
@@ -81,6 +81,15 @@ public class DeviceRegistry {
|
||||
throw new IOException("HTTP " + response.code());
|
||||
}
|
||||
String responseText = response.body().string();
|
||||
|
||||
// Validar que no sea HTML antes de parsear
|
||||
if (responseText != null) {
|
||||
String trimmed = responseText.trim();
|
||||
if (trimmed.startsWith("<!") || trimmed.startsWith("<html")) {
|
||||
throw new IOException("El servidor devolvió HTML en lugar de JSON");
|
||||
}
|
||||
}
|
||||
|
||||
JSONObject json = new JSONObject(responseText);
|
||||
JSONObject deviceJson = json.optJSONObject("device");
|
||||
JSONObject verificationJson = json.optJSONObject("verification");
|
||||
|
||||
@@ -79,19 +79,51 @@ public class EventRepository {
|
||||
connection.setConnectTimeout(15000);
|
||||
connection.setReadTimeout(15000);
|
||||
connection.setRequestMethod("GET");
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
connection.setRequestProperty("User-Agent", "StreamPlayer/1.0");
|
||||
|
||||
try {
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode != HttpURLConnection.HTTP_OK) {
|
||||
throw new IOException("Error HTTP " + responseCode + ": " + connection.getResponseMessage());
|
||||
}
|
||||
|
||||
String contentType = connection.getContentType();
|
||||
if (contentType != null && !contentType.contains("json")) {
|
||||
throw new IOException("El servidor devolvió " + contentType + " en lugar de JSON. Verifica que la URL sea correcta.");
|
||||
}
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
String response = builder.toString();
|
||||
|
||||
// Validar que no sea HTML
|
||||
if (response.trim().startsWith("<!") || response.trim().startsWith("<html")) {
|
||||
throw new IOException("El servidor devolvió HTML en lugar de JSON. La URL del endpoint puede estar incorrecta o el servidor tiene problemas.");
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
return builder.toString();
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private List<EventItem> parseEvents(String json) throws JSONException {
|
||||
if (json == null || json.trim().isEmpty()) {
|
||||
throw new JSONException("La respuesta está vacía");
|
||||
}
|
||||
|
||||
// Validar que no sea HTML antes de parsear
|
||||
String trimmed = json.trim();
|
||||
if (trimmed.startsWith("<!") || trimmed.startsWith("<html")) {
|
||||
throw new JSONException("Se recibió HTML en lugar de JSON");
|
||||
}
|
||||
|
||||
JSONArray array = new JSONArray(json);
|
||||
List<EventItem> events = new ArrayList<>();
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
@@ -100,8 +101,10 @@ public class PlayerActivity extends AppCompatActivity {
|
||||
try {
|
||||
String resolvedUrl = StreamUrlResolver.resolve(channelUrl);
|
||||
runOnUiThread(() -> startPlayback(resolvedUrl));
|
||||
} catch (IOException e) {
|
||||
runOnUiThread(() -> showError("No se pudo conectar con el canal: " + e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
runOnUiThread(() -> showError("Error al obtener stream: " + e.getMessage()));
|
||||
runOnUiThread(() -> showError("Error inesperado: " + e.getMessage()));
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@@ -61,15 +61,32 @@ public final class StreamUrlResolver {
|
||||
connection.setReadTimeout(15000);
|
||||
connection.setRequestProperty("User-Agent", USER_AGENT);
|
||||
connection.setRequestProperty("Accept", "text/html,application/xhtml+xml");
|
||||
connection.connect();
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
|
||||
try {
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode != HttpURLConnection.HTTP_OK) {
|
||||
throw new IOException("Error HTTP " + responseCode + " al cargar la página del stream");
|
||||
}
|
||||
|
||||
String contentType = connection.getContentType();
|
||||
// Validar que sea contenido web (HTML)
|
||||
if (contentType != null && !contentType.contains("html") && !contentType.contains("text")) {
|
||||
// A veces puede venir sin content type o application/octet-stream,
|
||||
// pero si es explícitamente una imagen o algo así, abortamos.
|
||||
if (contentType.startsWith("image/") || contentType.startsWith("video/") || contentType.startsWith("audio/")) {
|
||||
throw new IOException("El servidor devolvió " + contentType + " en lugar de HTML");
|
||||
}
|
||||
}
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
return builder.toString();
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
|
||||
@@ -172,6 +172,16 @@ public class UpdateManager {
|
||||
}
|
||||
|
||||
private UpdateInfo parseRelease(String responseBody) throws JSONException, IOException {
|
||||
if (responseBody == null || responseBody.trim().isEmpty()) {
|
||||
throw new JSONException("La respuesta está vacía");
|
||||
}
|
||||
|
||||
// Validar que no sea HTML antes de parsear
|
||||
String trimmed = responseBody.trim();
|
||||
if (trimmed.startsWith("<!") || trimmed.startsWith("<html")) {
|
||||
throw new JSONException("Se recibió HTML en lugar de JSON");
|
||||
}
|
||||
|
||||
JSONObject releaseJson = new JSONObject(responseBody);
|
||||
String tagName = releaseJson.optString("tag_name", "");
|
||||
String versionName = deriveVersionName(tagName, releaseJson.optString("name"));
|
||||
@@ -244,6 +254,11 @@ public class UpdateManager {
|
||||
}
|
||||
String json = response.body().string();
|
||||
if (!TextUtils.isEmpty(json)) {
|
||||
// Validar que no sea HTML antes de parsear
|
||||
String trimmed = json.trim();
|
||||
if (trimmed.startsWith("<!") || trimmed.startsWith("<html")) {
|
||||
continue;
|
||||
}
|
||||
return new JSONObject(json);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user