Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,8 @@ public void onClickLoginDone(final View view) {
HTTrackLib.LoginBundle bundle = null;
for (final String url : BrowserLoginPolicy.addressesToTry(web.getUrl(), openedUrl)) {
bundle = HTTrackLib.writeLoginBundle(result.text, bundleDir.getAbsolutePath(),
web.getSettings().getUserAgentString(), url);
web.getSettings().getUserAgentString(), url,
BrowserLoginPolicy.keptHosts(byHost.keySet()));
if (bundle != null) {
break;
}
Expand Down
17 changes: 17 additions & 0 deletions app/src/main/java/com/httrack/android/BrowserLoginPolicy.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -96,6 +97,22 @@ static String hostOf(final String url) {
return host.toLowerCase(Locale.ROOT);
}

/**
* Joins HOSTS into the comma-separated list the engine keeps cookies for.
*
* @param hosts
* the hosts that answered with a cookie, in the order they were asked
* @return the list, or null for none, which leaves the address's own cookies alone
*/
static String keptHosts(final Collection<String> hosts) {
final StringBuilder list = new StringBuilder();

for (final String host : hosts) {
list.append(list.length() == 0 ? "" : ",").append(host);
}
return list.length() == 0 ? null : list.toString();
}

/**
* The addresses to offer the engine for this login, best first. The login stops on the page
* the user wants copied, so that address leads. The engine refuses an address it cannot
Expand Down
5 changes: 4 additions & 1 deletion app/src/main/java/com/httrack/android/jni/HTTrackLib.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,13 @@ public LoginBundle(final String url, final int cookies, final int hosts) {
* the browser's User-Agent, sent to the bundle's sites alone
* @param url
* the address the login ended on
* @param hosts
* the hosts whose cookies to keep besides the address's own, comma-separated, or
* null to keep the address's own alone
* @return what it wrote, or null when the engine refused the login
*/
public static native LoginBundle writeLoginBundle(String paste, String folder, String agent,
String url);
String url, String hosts);

/**
* Has a native fault been recovered in this process ?
Expand Down
20 changes: 17 additions & 3 deletions app/src/main/jni/htslibjni.c
Original file line number Diff line number Diff line change
Expand Up @@ -696,8 +696,13 @@ JNICALL jobject Java_com_httrack_android_jni_HTTrackLib_writeLoginBundle(JNIEnv*
jstring opaste,
jstring ofolder,
jstring oagent,
jstring ourl) {
jstring ourl,
jstring ohosts) {
const char *paste, *folder, *agent, *url;
/* NULL is a value, not a mistake. It asks for the address's own cookies
alone. */
const char* hosts = NULL;
int got_hosts;
jobject bundle = NULL;

UNUSED(clazz);
Expand All @@ -716,12 +721,18 @@ JNICALL jobject Java_com_httrack_android_jni_HTTrackLib_writeLoginBundle(JNIEnv*
folder = (*env)->GetStringUTFChars(env, ofolder, NULL);
agent = (*env)->GetStringUTFChars(env, oagent, NULL);
url = (*env)->GetStringUTFChars(env, ourl, NULL);
if (paste != NULL && folder != NULL && agent != NULL && url != NULL) {
if (ohosts != NULL) {
hosts = (*env)->GetStringUTFChars(env, ohosts, NULL);
}
got_hosts = ohosts == NULL || hosts != NULL;
if (paste != NULL && folder != NULL && agent != NULL && url != NULL && got_hosts) {
hts_paste_result result;

memset(&result, 0, sizeof(result));
result.size = sizeof(result);
if (hts_bundle_from_paste(paste, folder, agent, url, HTS_FALSE, &result)) {
/* 0u: no HTS_PASTE_* flag. */
if (hts_bundle_from_paste_hosts(paste, folder, agent, url, hosts, 0u,
&result)) {
jstring written = (*env)->NewStringUTF(env, result.url);

if (written != NULL) {
Expand All @@ -733,6 +744,9 @@ JNICALL jobject Java_com_httrack_android_jni_HTTrackLib_writeLoginBundle(JNIEnv*
debug("the engine refused the login: %s", result.error);
}
}
if (hosts != NULL) {
(*env)->ReleaseStringUTFChars(env, ohosts, hosts);
}
if (url != NULL) {
(*env)->ReleaseStringUTFChars(env, ourl, url);
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/jni/httrack
Submodule httrack updated 75 files
+5 −5 .github/workflows/ci.yml
+1 −1 .github/workflows/sanitizer.yml
+4 −4 .github/workflows/tier2.yml
+1 −0 Makefile.am
+17 −9 html/faq.html
+28 −5 html/guide.html
+ − html/img/guide-droid-finished.png
+ − html/img/guide-droid-legacy-import.png
+ − html/img/guide-droid-opt-accept-headers.png
+ − html/img/guide-droid-opt-build.png
+ − html/img/guide-droid-opt-flow-control.png
+ − html/img/guide-droid-opt-limits.png
+ − html/img/guide-droid-opt-scan-rules.png
+ − html/img/guide-droid-options-menu.png
+ − html/img/guide-droid-permission.png
+ − html/img/guide-droid-progress.png
+ − html/img/guide-droid-project-setup.png
+ − html/img/guide-droid-start.png
+ − html/img/guide-web-add-url.png
+ − html/img/guide-web-finished.png
+ − html/img/guide-web-opt-browser-id.png
+ − html/img/guide-web-opt-build.png
+ − html/img/guide-web-opt-experts-only.png
+ − html/img/guide-web-opt-flow-control.png
+ − html/img/guide-web-opt-limits.png
+ − html/img/guide-web-opt-links.png
+ − html/img/guide-web-opt-log-index-cache.png
+ − html/img/guide-web-opt-mime-types.png
+ − html/img/guide-web-opt-proxy.png
+ − html/img/guide-web-opt-scan-rules.png
+ − html/img/guide-web-opt-spider.png
+ − html/img/guide-web-progress.png
+ − html/img/guide-web-project-name.png
+ − html/img/guide-web-project-setup.png
+ − html/img/guide-web-ready.png
+ − html/img/guide-web-start.png
+ − html/img/guide-win-add-url.png
+ − html/img/guide-win-finished.png
+ − html/img/guide-win-language.png
+ − html/img/guide-win-opt-browser-id.png
+ − html/img/guide-win-opt-flow-control.png
+ − html/img/guide-win-opt-limits.png
+ − html/img/guide-win-opt-scan-rules.png
+ − html/img/guide-win-progress.png
+ − html/img/guide-win-project-name.png
+ − html/img/guide-win-project-setup.png
+ − html/img/guide-win-ready.png
+ − html/img/guide-win-start.png
+1 −1 html/index.html
+85 −22 html/login.html
+1 −1 src/coucal
+356 −87 src/htsbundle.c
+20 −11 src/htsbundle_selftest.c
+2 −0 src/htscore.c
+6 −0 src/htscore.h
+80 −1 src/htshash.c
+11 −0 src/htshash.h
+17 −1 src/htslib_selftest.c
+182 −84 src/htsname.c
+225 −0 src/htsname_selftest.c
+2 −1 src/htswarc.c
+3 −0 src/htswarc_selftest.c
+19 −4 src/httrack-library.h
+17 −0 tests/01_engine-savename.test
+14 −1 tests/208_install-headers-advertised.test
+24 −0 tests/226_watchdog-native.test
+9 −9 tests/279_doc-guide-image-sizes.test
+15 −1 tests/659_engine-y2038.test
+54 −0 tests/695_ci-test-log.test
+245 −0 tests/696_engine-bundle-paste-hosts.test
+4 −3 tests/72_watchdog-crawl.test
+1 −1 tests/local-crawl.sh
+1 −0 tests/testlib.sh
+34 −0 tools/ci-test-log.sh
+13 −9 tools/doc-images.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.httrack.android;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
Expand Down Expand Up @@ -105,17 +106,21 @@ public void theCapsKeepEveryLineUnderTheEnginesLineMax() throws IOException {
*/
@Test
public void theBundleWriterIsAnExportedEngineCallThatReadsItsOwnOutputBack() throws IOException {
assertTrue("the JNI calls the flags entry point now, so this test reads the wrong function",
TestSources.read(TestSources.mainFile("jni/htslibjni.c")).contains(
"hts_bundle_from_paste(paste, folder, agent, url"));
assertTrue("hts_bundle_from_paste is no longer exported",
source("httrack-library.h").contains("HTSEXT_API hts_boolean hts_bundle_from_paste("));
/* Comments and spacing stripped, so reflowing the call cannot fail this. The argument
list is pinned whole, because the same call with a NULL hosts keeps the older
behaviour and reads as the fix. */
final String jni = TestSources.withoutCommentsAndStrings(
TestSources.read(TestSources.mainFile("jni/htslibjni.c"))).replaceAll("\\s+", " ");
assertTrue(jni, jni.contains(
"hts_bundle_from_paste_hosts(paste, folder, agent, url, hosts, 0u, &result)"));
assertFalse("the entry point without a hosts list keeps no intermediate cookies",
jni.contains("hts_bundle_from_paste(paste,"));
assertTrue("hts_bundle_from_paste_hosts is no longer exported",
source("httrack-library.h").contains(
"HTSEXT_API hts_boolean hts_bundle_from_paste_hosts("));
final String paste = source("htsbundle.c");
final String wrapper = TestSources.balancedBlock(paste,
TestSources.indexOf(paste, "HTSEXT_API hts_boolean hts_bundle_from_paste("));
assertTrue(wrapper, wrapper.contains("return hts_bundle_from_paste_flags("));
final String body = TestSources.balancedBlock(paste,
TestSources.indexOf(paste, "HTSEXT_API hts_boolean hts_bundle_from_paste_flags("));
TestSources.indexOf(paste, "HTSEXT_API hts_boolean hts_bundle_from_paste_hosts("));
// Failing has to be the guard's whole statement, or a bundle the read-back rejected still
// reaches the folder.
final int read = TestSources.indexOf(body, "!bundle_load_src(");
Expand Down
18 changes: 18 additions & 0 deletions app/src/test/java/com/httrack/android/BrowserLoginPolicyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,24 @@ public void theTypedCredentialsDoNotTravelToAnotherHost() {
assertEquals(cleartext, named("https://user:pw@a.example/", cleartext));
}

/**
* The login keeps the cookies of every host that answered with one, so a crawl can
* authenticate on a site the login passed through.
*/
@Test
public void everyHostThatAnsweredWithACookieIsNamed() {
assertEquals("a.example,idp.example",
BrowserLoginPolicy.keptHosts(Arrays.asList("a.example", "idp.example")));
// The engine's separator is a comma, and nothing else.
assertEquals("a.example", BrowserLoginPolicy.keptHosts(Arrays.asList("a.example")));
}

/** Naming no host asks the engine for the address's own cookies alone, as it did before. */
@Test
public void namingNoHostKeepsTheEnginesOlderBehaviour() {
assertNull(BrowserLoginPolicy.keptHosts(new ArrayList<String>()));
}

/**
* The landed address leads, because that is the page to copy. The opened one follows, so a
* landed address the engine refuses still leaves a login to save.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,15 @@ public void theBundleIsNamedForTheAddressTheLoginLandedOn() throws IOException {
TestSources.indexOf(source, "public void onClickLoginDone("));
assertTrue(done, done.contains("BrowserLoginPolicy.addressesToTry(web.getUrl(), openedUrl)"));
// The loop's own address, or every attempt would name the one the window was opened for.
assertTrue(done, done.contains("getUserAgentString(), url);"));
assertTrue(done, done.contains("getUserAgentString(), url,"));
// The loop stops at the first address the engine accepts, rather than at the last.
assertTrue(done, done.contains("if (bundle != null) {\n break;"));
final String create = TestSources.balancedBlock(source,
TestSources.indexOf(source, "protected void onCreate("));
assertTrue(create, create.contains("openedUrl = BrowserLoginPolicy.withoutUserInfo(url)"));
/* The hosts that answered, not the hosts asked: a host with no cookie carries nothing
to keep, and naming it would widen the bundle's scope for nothing. */
assertTrue(done, done.contains("BrowserLoginPolicy.keptHosts(byHost.keySet())"));
final String caller = TestSources
.withoutCommentsAndStrings(TestSources.javaSource("HTTrackActivity"));
final String apply = TestSources.balancedBlock(caller,
Expand Down
Loading