fix: 🐛 Refactoring and simpler registering of custom cookie jar

This commit is contained in:
Erik Hellman 2021-03-31 07:26:03 +02:00
parent f488ab6b61
commit e78350414a
4 changed files with 118 additions and 139 deletions

View File

@ -8,16 +8,16 @@ import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.OkHttpClientFactory;
import com.facebook.react.modules.network.OkHttpClientProvider;
import com.facebook.soloader.SoLoader;
import org.skolplattformen.modules.OkHttpClientFactoryCustom;
import java.lang.reflect.InvocationTargetException;
import java.net.CookieManager;
import java.util.List;
import okhttp3.OkHttpClient;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@ -53,8 +53,16 @@ public class MainApplication extends Application implements ReactApplication {
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
ReactInstanceManager mReactInstanceManager = getReactNativeHost().getReactInstanceManager();
mReactInstanceManager.addReactInstanceEventListener(reactContext ->
OkHttpClientProvider.setOkHttpClientFactory(new OkHttpClientFactoryCustom(reactContext)));
mReactInstanceManager.addReactInstanceEventListener(reactContext -> {
OkHttpClientProvider.setOkHttpClientFactory(new OkHttpClientFactory() {
@Override
public OkHttpClient createNewNetworkModuleClient() {
return OkHttpClientProvider.createClientBuilder(reactContext)
.cookieJar(new SkolplattformenCookieJar(new CookieManager()))
.build();
}
});
});
}

View File

@ -0,0 +1,104 @@
package org.skolplattformen.app;
import androidx.annotation.NonNull;
import java.io.IOException;
import java.net.CookieHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import okhttp3.internal.platform.Platform;
import static okhttp3.internal.Util.delimiterOffset;
import static okhttp3.internal.Util.trimSubstring;
import static okhttp3.internal.platform.Platform.WARN;
public final class SkolplattformenCookieJar implements CookieJar {
public static final String HEADER_COOKIE_2 = "Cookie2";
public static final String HEADER_COOKIE = "Cookie";
public static final String HEADER_SET_COOKIE = "Set-Cookie";
private final CookieHandler cookieHandler;
public SkolplattformenCookieJar(CookieHandler cookieHandler) {
this.cookieHandler = cookieHandler;
}
@Override
public void saveFromResponse(@NonNull HttpUrl url, @NonNull List<Cookie> cookies) {
if (cookieHandler != null) {
List<String> cookieStrings = new ArrayList<>();
for (Cookie cookie : cookies) {
cookieStrings.add(cookie.toString());
}
Map<String, List<String>> multimap = Collections.singletonMap(HEADER_SET_COOKIE, cookieStrings);
try {
cookieHandler.put(url.uri(), multimap);
} catch (IOException e) {
Platform.get().log(WARN, "Saving cookies failed for " + url.resolve("/..."), e);
}
}
}
@Override
@NonNull
public List<Cookie> loadForRequest(@NonNull HttpUrl url) {
// The RI passes all headers. We don't have 'em, so we don't pass 'em!
Map<String, List<String>> headers = Collections.emptyMap();
Map<String, List<String>> cookieHeaders;
try {
cookieHeaders = cookieHandler.get(url.uri(), headers);
} catch (IOException e) {
Platform.get().log(WARN, "Loading cookies failed for " + url.resolve("/..."), e);
return Collections.emptyList();
}
List<Cookie> cookies = null;
for (Map.Entry<String, List<String>> entry : cookieHeaders.entrySet()) {
String key = entry.getKey();
if ((HEADER_COOKIE.equalsIgnoreCase(key) || HEADER_COOKIE_2.equalsIgnoreCase(key))
&& !entry.getValue().isEmpty()) {
for (String header : entry.getValue()) {
if (cookies == null) cookies = new ArrayList<>();
cookies.addAll(decodeHeaderAsJavaNetCookies(url, header));
}
}
}
return cookies != null
? Collections.unmodifiableList(cookies)
: Collections.emptyList();
}
private List<Cookie> decodeHeaderAsJavaNetCookies(HttpUrl url, String header) {
List<Cookie> result = new ArrayList<>();
for (int pos = 0, limit = header.length(), pairEnd; pos < limit; pos = pairEnd + 1) {
pairEnd = delimiterOffset(header, pos, limit, ";");
int equalsSign = delimiterOffset(header, pos, pairEnd, '=');
String name = trimSubstring(header, pos, equalsSign);
if (name.startsWith("$")) continue;
// We have either name=value or just a name.
String value = equalsSign < pairEnd
? trimSubstring(header, equalsSign + 1, pairEnd)
: "";
// If the value is "quoted", drop the quotes.
if (value.startsWith("\"") && value.endsWith("\"")) {
value = value.substring(1, value.length() - 1);
}
result.add(new Cookie.Builder()
.name(name)
.value(value)
.domain(url.host())
.build());
}
return result;
}
}

View File

@ -1,96 +0,0 @@
package org.skolplattformen.modules;
import java.io.IOException;
import java.net.CookieHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import okhttp3.internal.platform.Platform;
import static okhttp3.internal.Util.delimiterOffset;
import static okhttp3.internal.Util.trimSubstring;
import static okhttp3.internal.platform.Platform.WARN;
final class CookieJarCustom implements CookieJar {
private final CookieHandler cookieHandler;
public CookieJarCustom(CookieHandler cookieHandler) {
this.cookieHandler = cookieHandler;
}
@Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
if (cookieHandler != null) {
List<String> cookieStrings = new ArrayList<>();
for (Cookie cookie : cookies) {
cookieStrings.add(cookie.toString());
}
Map<String, List<String>> multimap = Collections.singletonMap("Set-Cookie", cookieStrings);
try {
cookieHandler.put(url.uri(), multimap);
} catch (IOException e) {
Platform.get().log(WARN, "Saving cookies failed for " + url.resolve("/..."), e);
}
}
}
@Override public List<Cookie> loadForRequest(HttpUrl url) {
// The RI passes all headers. We don't have 'em, so we don't pass 'em!
Map<String, List<String>> headers = Collections.emptyMap();
Map<String, List<String>> cookieHeaders;
try {
cookieHeaders = cookieHandler.get(url.uri(), headers);
} catch (IOException e) {
Platform.get().log(WARN, "Loading cookies failed for " + url.resolve("/..."), e);
return Collections.emptyList();
}
List<Cookie> cookies = null;
for (Map.Entry<String, List<String>> entry : cookieHeaders.entrySet()) {
String key = entry.getKey();
if (("Cookie".equalsIgnoreCase(key) || "Cookie2".equalsIgnoreCase(key))
&& !entry.getValue().isEmpty()) {
for (String header : entry.getValue()) {
if (cookies == null) cookies = new ArrayList<>();
cookies.addAll(decodeHeaderAsJavaNetCookies(url, header));
}
}
}
return cookies != null
? Collections.unmodifiableList(cookies)
: Collections.emptyList();
}
private List<Cookie> decodeHeaderAsJavaNetCookies(HttpUrl url, String header) {
List<Cookie> result = new ArrayList<>();
for (int pos = 0, limit = header.length(), pairEnd; pos < limit; pos = pairEnd + 1) {
pairEnd = delimiterOffset(header, pos, limit, ";");
int equalsSign = delimiterOffset(header, pos, pairEnd, '=');
String name = trimSubstring(header, pos, equalsSign);
if (name.startsWith("$")) continue;
// We have either name=value or just a name.
String value = equalsSign < pairEnd
? trimSubstring(header, equalsSign + 1, pairEnd)
: "";
// If the value is "quoted", drop the quotes.
if (value.startsWith("\"") && value.endsWith("\"")) {
value = value.substring(1, value.length() - 1);
}
result.add(new Cookie.Builder()
.name(name)
.value(value)
.domain(url.host())
.build());
}
return result;
}
}

View File

@ -1,37 +0,0 @@
package org.skolplattformen.modules;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.ForwardingCookieHandler;
import com.facebook.react.modules.network.OkHttpClientFactory;
import com.facebook.react.modules.network.OkHttpClientProvider;
import com.facebook.react.modules.network.ReactCookieJarContainer;
import okhttp3.CookieJar;
import okhttp3.OkHttpClient;
public class OkHttpClientFactoryCustom implements OkHttpClientFactory {
private final ReactContext context;
public OkHttpClientFactoryCustom(ReactContext context) {
super();
this.context = context;
}
@Override
public OkHttpClient createNewNetworkModuleClient() {
OkHttpClient.Builder builder = OkHttpClientProvider.createClientBuilder(this.context);
CookieJarCustom cookieJarCustom = new CookieJarCustom(new ForwardingCookieHandler(this.context));
builder.cookieJar(new ReactCookieJarContainer() {
@Override
public void setCookieJar(CookieJar cookieJar) {
super.setCookieJar(cookieJarCustom);
}
});
return builder.build();
}
}