GingerCal 1.4: bundled TLS 1.2, no bridge needed
CalDAV now goes through Minamp's own HTTP/TLS client (Bouncy Castle TLS 1.2, Mozilla roots, keep-alive) instead of Apache HttpClient on Android 2.3's TLS 1.0, as the iPod version does with BearSSL. The phone reaches the normal https:// Nextcloud address at home and away; a pinned self-signed server or the old bridge still works. - NetHttp transport; requests run on big-stack threads (the handshake overflows AsyncTask/IntentService stacks on Android 2.x) - http:// -> https:// redirects on the same host are followed; other hosts still refused - bridge wording replaced in Galician and English; README updated - NetTest (TLS + CalDAV discovery through the new transport) replaces BridgeTest Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
42c3d6da91
commit
f7428287eb
145 files changed
+1278
-407
No files matched your search
@@ -0,0 +1,78 @@
|
||||
package org.gingercal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.gingercal.net.CertVerifier;
|
||||
|
||||
/**
|
||||
* Android 2.3 transport through the bundled TLS 1.2 client (org.gingercal.net, from Minamp):
|
||||
* the phone's own TLS 1.0 can't reach Nextcloud, so this talks to the normal https:// address
|
||||
* directly, any method (PROPFIND/REPORT included), with keep-alive. A pinned certificate (a
|
||||
* self-signed server or an old bridge) is still honoured.
|
||||
*/
|
||||
public class NetHttp implements Http {
|
||||
/** AsyncTask and IntentService threads have Android 2.x's small default stack, which the
|
||||
* TLS handshake overflows: requests run here, on big-stack threads, and the caller waits. */
|
||||
private static final ExecutorService NET = org.gingercal.net.Threads.pool("net", 3);
|
||||
|
||||
final String pin;
|
||||
final int timeoutMs;
|
||||
|
||||
public NetHttp(String pin, int timeoutMs) {
|
||||
this.pin = pin == null ? "" : pin;
|
||||
this.timeoutMs = timeoutMs;
|
||||
}
|
||||
|
||||
public Resp exec(final String method, final String url, final String[] headers, final String body,
|
||||
final String contentType) throws IOException {
|
||||
try {
|
||||
return NET.submit(new Callable<Resp>() {
|
||||
public Resp call() throws IOException {
|
||||
return execHere(method, url, headers, body, contentType);
|
||||
}
|
||||
}).get();
|
||||
} catch (ExecutionException e) {
|
||||
Throwable c = e.getCause();
|
||||
if (c instanceof IOException) throw (IOException) c;
|
||||
if (c instanceof RuntimeException) throw (RuntimeException) c;
|
||||
if (c instanceof Error) throw (Error) c;
|
||||
throw new IOException(String.valueOf(c));
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException(L.t("Interrupted"));
|
||||
}
|
||||
}
|
||||
|
||||
Resp execHere(String method, String url, String[] headers, String body, String contentType)
|
||||
throws IOException {
|
||||
CertVerifier.setPin(pin);
|
||||
Map<String, String> h = new LinkedHashMap<String, String>();
|
||||
for (int i = 0; i + 1 < headers.length; i += 2) h.put(headers[i], headers[i + 1]);
|
||||
byte[] data = null;
|
||||
if (body != null) {
|
||||
data = body.getBytes("UTF-8");
|
||||
if (contentType != null) h.put("Content-Type", contentType);
|
||||
}
|
||||
org.gingercal.net.Http.Response r;
|
||||
try {
|
||||
// one hop at a time: Dav decides which redirects are safe to follow
|
||||
r = org.gingercal.net.Http.requestNoRedirect(method, url, h, data, timeoutMs);
|
||||
} catch (CertVerifier.Untrusted u) {
|
||||
throw new DavException.UntrustedCert(u.fingerprint, u.subject, u.issuer, u.expires, u.changed);
|
||||
}
|
||||
Resp out = new Resp();
|
||||
out.code = r.code;
|
||||
out.etag = r.header("etag");
|
||||
out.location = r.header("location");
|
||||
out.body = r.readString();
|
||||
return out;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
// pooled connections are shared and expire by themselves
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user