|
|
|
@ -1,5 +1,7 @@
|
|
|
|
|
package com.fox2code.mmm.utils;
|
|
|
|
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.SharedPreferences;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
@ -13,9 +15,11 @@ import java.io.InputStream;
|
|
|
|
|
import java.net.InetAddress;
|
|
|
|
|
import java.net.Proxy;
|
|
|
|
|
import java.net.UnknownHostException;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
import java.util.Iterator;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Objects;
|
|
|
|
@ -34,6 +38,7 @@ import okhttp3.brotli.BrotliInterceptor;
|
|
|
|
|
import okhttp3.dnsoverhttps.DnsOverHttps;
|
|
|
|
|
|
|
|
|
|
public class Http {
|
|
|
|
|
private static final String TAG = "Http";
|
|
|
|
|
private static final OkHttpClient httpClient;
|
|
|
|
|
private static final OkHttpClient httpClientWithCache;
|
|
|
|
|
|
|
|
|
@ -70,28 +75,34 @@ public class Http {
|
|
|
|
|
Objects.requireNonNull(HttpUrl.parse("https://cloudflare-dns.com/dns-query")))
|
|
|
|
|
.bootstrapDnsHosts(cloudflareBootstrap).resolvePrivateAddresses(true).build();
|
|
|
|
|
} catch (UnknownHostException|RuntimeException e) {
|
|
|
|
|
Log.e("Http", "Failed to init DoH", e);
|
|
|
|
|
Log.e(TAG, "Failed to init DoH", e);
|
|
|
|
|
}
|
|
|
|
|
httpclientBuilder.cookieJar(CookieJar.NO_COOKIES);
|
|
|
|
|
httpclientBuilder.dns(dns);
|
|
|
|
|
httpClient = httpclientBuilder.build();
|
|
|
|
|
MainApplication mainApplication = MainApplication.getINSTANCE();
|
|
|
|
|
if (mainApplication != null) {
|
|
|
|
|
httpclientBuilder.dns(new FallBackDNS(mainApplication, dns, "github.com",
|
|
|
|
|
"api.github.com", "raw.githubusercontent.com", "camo.githubusercontent.com",
|
|
|
|
|
"user-images.githubusercontent.com", "cdn.jsdelivr.net", "img.shields.io",
|
|
|
|
|
"magisk-modules-repo.github.io", "www.androidacy.com"));
|
|
|
|
|
httpClient = httpclientBuilder.build();
|
|
|
|
|
httpclientBuilder.cache(new Cache(
|
|
|
|
|
new File(mainApplication.getCacheDir(), "http_cache"),
|
|
|
|
|
2L * 1024L * 1024L)); // 2Mib of cache
|
|
|
|
|
httpclientBuilder.cookieJar(new CDNCookieJar());
|
|
|
|
|
httpClientWithCache = httpclientBuilder.build();
|
|
|
|
|
Log.i(TAG, "Initialized Http successfully!");
|
|
|
|
|
} else {
|
|
|
|
|
httpClientWithCache = httpClient;
|
|
|
|
|
httpclientBuilder.dns(dns);
|
|
|
|
|
httpClientWithCache = httpClient = httpclientBuilder.build();
|
|
|
|
|
Log.e(TAG, "Initialized Http too soon!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static OkHttpClient getHttpclientNoCache() {
|
|
|
|
|
public static OkHttpClient getHttpClient() {
|
|
|
|
|
return httpClient;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static OkHttpClient getHttpclientWithCache() {
|
|
|
|
|
public static OkHttpClient getHttpClientWithCache() {
|
|
|
|
|
return httpClientWithCache;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -207,4 +218,85 @@ public class Http {
|
|
|
|
|
public interface ProgressListener {
|
|
|
|
|
void onUpdate(int downloaded,int total, boolean done);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* FallBackDNS store successful DNS request to return them later
|
|
|
|
|
* can help make the app to work later when the current DNS system
|
|
|
|
|
* isn't functional or available.
|
|
|
|
|
*
|
|
|
|
|
* Note: DNS Cache is stored in user data.
|
|
|
|
|
* */
|
|
|
|
|
private static class FallBackDNS implements Dns {
|
|
|
|
|
private final Dns parent;
|
|
|
|
|
private final SharedPreferences sharedPreferences;
|
|
|
|
|
private final HashSet<String> fallbacks;
|
|
|
|
|
private final HashMap<String, List<InetAddress>> fallbackCache;
|
|
|
|
|
|
|
|
|
|
public FallBackDNS(Context context, Dns parent, String... fallbacks) {
|
|
|
|
|
this.sharedPreferences = context.getSharedPreferences(
|
|
|
|
|
"mmm_dns", Context.MODE_PRIVATE);
|
|
|
|
|
this.parent = parent;
|
|
|
|
|
this.fallbacks = new HashSet<>(Arrays.asList(fallbacks));
|
|
|
|
|
this.fallbackCache = new HashMap<>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
|
@Override
|
|
|
|
|
public List<InetAddress> lookup(@NonNull String s) throws UnknownHostException {
|
|
|
|
|
if (this.fallbacks.contains(s)) {
|
|
|
|
|
List<InetAddress> addresses = this.fallbackCache.get(s);
|
|
|
|
|
if (addresses != null)
|
|
|
|
|
return addresses;
|
|
|
|
|
try {
|
|
|
|
|
addresses = this.parent.lookup(s);
|
|
|
|
|
if (addresses.isEmpty() || addresses.get(0).isLoopbackAddress())
|
|
|
|
|
throw new UnknownHostException(s);
|
|
|
|
|
this.fallbackCache.put(s, addresses);
|
|
|
|
|
this.sharedPreferences.edit().putString(
|
|
|
|
|
s.replace('.', '_'), toString(addresses)).apply();
|
|
|
|
|
} catch (UnknownHostException e) {
|
|
|
|
|
String key = this.sharedPreferences.getString(
|
|
|
|
|
s.replace('.', '_'), "");
|
|
|
|
|
if (!key.isEmpty()) try {
|
|
|
|
|
addresses = fromString(key);
|
|
|
|
|
this.fallbackCache.put(s, addresses);
|
|
|
|
|
return addresses;
|
|
|
|
|
} catch (UnknownHostException e2) {
|
|
|
|
|
this.sharedPreferences.edit().remove(
|
|
|
|
|
s.replace('.', '_')).apply();
|
|
|
|
|
}
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return addresses;
|
|
|
|
|
} else {
|
|
|
|
|
return this.parent.lookup(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
|
private static String toString(@NonNull List<InetAddress> inetAddresses) {
|
|
|
|
|
if (inetAddresses.isEmpty()) return "";
|
|
|
|
|
Iterator<InetAddress> inetAddressIterator = inetAddresses.iterator();
|
|
|
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
|
|
|
while (true) {
|
|
|
|
|
stringBuilder.append(inetAddressIterator.next().getHostAddress());
|
|
|
|
|
if (!inetAddressIterator.hasNext())
|
|
|
|
|
return stringBuilder.toString();
|
|
|
|
|
stringBuilder.append("|");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
|
private static List<InetAddress> fromString(@NonNull String string)
|
|
|
|
|
throws UnknownHostException {
|
|
|
|
|
if (string.isEmpty()) return Collections.emptyList();
|
|
|
|
|
String[] strings = string.split("\\|");
|
|
|
|
|
ArrayList<InetAddress> inetAddresses = new ArrayList<>(strings.length);
|
|
|
|
|
for (String address : strings) {
|
|
|
|
|
inetAddresses.add(InetAddress.getByName(address));
|
|
|
|
|
}
|
|
|
|
|
return inetAddresses;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|