diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml
new file mode 100644
index 00000000000..38a738feaad
--- /dev/null
+++ b/.github/workflows/package.yml
@@ -0,0 +1,68 @@
+name: Build debian package
+on:
+ push:
+ branches: [ 'master', 'next', 'debian-package' ]
+ tags:
+ - build**
+ - testing-**
+ pull_request:
+jobs:
+ build-deb:
+ strategy:
+ matrix:
+ os: [ubuntu-latest]
+ distribution: [temurin]
+ java: [17]
+
+ runs-on: '${{ matrix.os }}'
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Wrapper validation
+ uses: gradle/actions/wrapper-validation@v4
+
+ - name: Speedup dpkg
+ run: sudo sh -c "echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/force-unsafe-io"
+
+ - name: Fix 'Setup Java' action Gradle caching
+ run: |
+ sudo mkdir -p /tmp/fred-build/gradle
+ sudo ln -s /tmp/fred-build/gradle ~/.gradle
+ sudo chmod o+rwx ~/.gradle
+
+ - name: Setup Java
+ uses: actions/setup-java@v4
+ with:
+ cache: 'gradle'
+ distribution: '${{ matrix.distribution }}'
+ java-version: '${{ matrix.java }}'
+
+ - name: Install dependencies
+ run: |
+ sudo apt update
+ sudo apt install build-essential debhelper devscripts equivs -y
+
+ - name: Install package build dependencies
+ run: |
+ install_tool="apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes"
+ sudo mk-build-deps --install -r --tool="${install_tool}" debian/control
+
+ - name: Build package
+ run: |
+ sudo gbp buildpackage --git-ignore-branch --git-upstream-tag="HEAD" -us -uc --git-ignore-new || (EDITOR=true dpkg-source --commit . hack-1 && sudo gbp buildpackage --git-ignore-branch --git-upstream-tag="HEAD" -us -uc --git-ignore-new)
+
+ - name: Get package info
+ run: |
+ dpkg -I ../freenet*.deb
+ file ../freenet*.deb
+ cp ../freenet*.deb ./
+
+ - name: Provide Debian Package
+ uses: actions/upload-artifact@v4
+ with:
+ name: debian-package
+ path: freenet_*.deb
+ # Since .deb file is compressed archive itself,
+ # additional compression useless
+ compression-level: 0
diff --git a/.gitignore b/.gitignore
index 48cba0bb50a..fd13d826f15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,8 +15,21 @@
*.iml
*.ipr
*.iws
-.*
*~
\#*\#
/override.properties
/gradle.properties
+debhelper-build-stamp
+.debhelper
+*.deb
+*.dsc
+*.build
+*.buildinfo
+*.changes
+*.tar.gz
+*.log
+*.substvars
+/debian/freenet/*
+.gradle
+gradle
+debian/seednodes.fref
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 9a6d18de93d..99dc521444b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -11,9 +11,9 @@ start with:
List only bugs filed against this repository by selecting "Freenet" in the
"Project" drop-down in the upper right. Do any of these look interesting?
* Check the [projects](https://wiki.freenetproject.org/Projects) page.
-* Ask the [development mailing list](https://emu.freenetproject.org/cgi-bin/mailman/listinfo/devl)
- or join us in [IRC](https://freenetproject.org/irc.html) - `#freenet` on
- `chat.freenode.net`.
+* Ask the [development mailing list](https://freenetproject.org/pages/help.html#mailing-lists)
+ or join us in [IRC](https://web.libera.chat/?nick=Rabbit|?#freenet) - `#freenet` on
+ `irc.libera.chat`.
# Code review
@@ -23,8 +23,7 @@ against the `next` branch. It's usually a good idea to work on a topic / feature
branch that starts at `next` and is specific to the pull request. Once you have
submitted a pull request, people will start reviewing it and providing feedback.
If you don't hear anything for a while feel free to bring it to the attention of
-people in [IRC](https://freenetproject.org/irc.html) or the [mailing
-list](https://emu.freenetproject.org/cgi-bin/mailman/listinfo/devl) - we may
+people in [IRC](https://www.hyphanet.org/pages/help.html#chat-with-us) or the [mailing list](https://www.hyphanet.org/pages/help.html#mailing-lists) - we may
have missed it.
Code review helps improve code quality, ensures that multiple people know the
@@ -37,8 +36,8 @@ producing software that is readable, correct, and sufficiently efficient.
Breaking API creates an immense amount of work for developers of other projects,
so it is *not* something to be done lightly. If you feel you must make a change
that breaks API and cannot maintain backwards compatibility, please first raise
-the issue with the community - the [mailing list](https://emu.freenetproject.org/cgi-bin/mailman/listinfo/devl)
-and [IRC](https://freenetproject.org/irc.html) are good places to contact us.
+the issue with the community - the [mailing list](https://www.hyphanet.org/pages/help.html#mailing-lists)
+and [IRC](https://www.hyphanet.org/pages/help.html#chat-with-us) are good places to contact us.
Changing dependencies must be accompanied with changes in every
installer and updates to `dependencies.properties` and existing
diff --git a/NEWS.md b/NEWS.md
index 5365f1c7289..69acacc222f 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,6 +1,253 @@
next:
--
+- Update Gradle to 8.9 thanks to Christophe!
+- replace length = 0 checks with isEmpty() — thanks to Juiceman!
+- do not recommend disabling js helpers in fproxy (these are reviewed)
+- add more resilient plugin list exception handling
+- Remove gc meddling that hasn’t been necessary for many Java releases
+- Add webp filter, thanks to Torusrxxx!
+- Update Japanese localization, thanks to qupo1!
+- Fix build info with gradle daemon, thanks to Bombe!
+- Improve IPv6 handling, thanks to Torusrxxx!
+- Hide no longer relevant new load management statistics, thanks to Torusrxxx!
+
+1498:
+
+# Short changelog:
+
+This release resolves the last blocker for Freenet / Hyphanet 0.8 by
+providing an official Debian package. Additionally it optimizes the
+networking and data transfer core and provides many improvements for
+website authors and user experience.
+
+
+Starting with this release, Freenet / Hyphanet has an official Debian
+package built automatically via github actions. This was the most
+important [high-impact-task][] and the last release blocker of version
+0.8 in our [Roadmap][]. Big thanks go to DC*!
+
+With this finally realized, the next step is to get in contact with
+the many privacy focussed distributions which build on Debian to make
+`hyphanet-fred` available where it is most important. Once this is
+done, tools which build on Hyphanet — like FMS, but also jSite and
+tools from pyFreenet — can be packaged to work out of the box, using
+Hyphanet as an ordinary background service. That’s a step towards
+Hyphanet as decentralized, privacy-preserving communication backend for
+other applications.
+
+Another step towards this is accepting the Schema hypha[net] to
+simplify writing browser extensions that forward hypha:-links to
+Hyphanet.
+
+
+The networking layer was optimized significantly. Searching packet
+types is often stopped early and common or cheaper checks are done
+before less common or time-consuming checks. This gives significant
+reductions of CPU load, especially for very fast nodes.
+
+Juiceman fixed a bug limiting MTU to 1280 where not needed.
+
+And recently failed and data not found cooldown times were reduced to
+5 minutes and 3 minutes, reducing one of the big annoyances when
+accessing a site quickly after upload.
+
+On the data transfer layer, healing was optimized. After 1495 strongly
+increased the amount of healing to keep large files available for
+longer, 1498 specializes healing to keys close to the node location.
+This reduces healing per file, but improves privacy, because healing
+inserts are then more similar to forwarding — they mostly send data
+close to the nodes location — and it reduces the network load of
+healing, because the specialized healing inserts need fewer hops to
+reach the optimal storage location in the network.
+
+
+In addition to these changes deep down, there are a number of directly
+visible improvements.
+
+The plugins KeepAlive and Sharesite are updated (the latter now uses
+the new Night Zen Garden style). The UPnP2 plugin is now visible in
+simple mode. It can replace UPnP and should work better. On the
+flipside the Library plugin is moved to advanced plugins, because it
+does not work reliably enough.
+
+The plugin list is easier to navigate by removing the defunct option
+to download plugins from the clearnet and by adding better styling.
+Downloading from the clearnet was an unnecessary privacy risk since
+we’ve been bundling essential plugins with the installer for a few
+years now.
+
+
+The noderef for friend-to-friend connections is shown in simple mode
+again, because it is robust enough with the changes in recent years.
+This should remove a barrier to adding direct connections and enabling
+fully confidential messages between friends.
+
+There are new configuration options to allow connecting via local
+services. That’s a step towards making it easy to add a second layer
+of security, for example confining connections to a local network.
+Thanks goes to s7r for these changes!
+
+When bandwidth detection fails, the upload bandwidth now defaults to
+160KiB/s. Also the NLM config is now disabled statically. This was a
+testing setup which could still be active in old nodes, but it would
+break connectivity nowadays.
+
+
+The default bookmarks include the Opennet SeedNodes statistics,
+the generate media site to create decentralized streaming sites, and
+the high-impact-tasks. The bookmarks are also re-ordered to be a
+better match for newcomers. Starting category: first steps, clean
+spider, Index of Indexes. For the software category ordered by ease of
+use from fproxy.
+
+For website authors, more CSS elements, selectors and combinators
+(`:checked`, `word-wrap: anywhere`, `focus-within`, `^=`, `$=`, `*=`,
+`>`, `+`, `~`) and additional HTML elements (`summary`, `details`,
+``) are available. This strongly expands the
+possibilities of websites authors in Hyphanet, because Javascript or
+webassembly are no viable options in an environment where a privacy
+breach could put people at risk. We’ve seen with Java applets, that
+untrusted code will always break out of its containment. The CSS
+improvements in contrast provide a safe way to enable limited
+interactivity.
+
+Streaming support via m3u lists was improved to allow accessing
+segments of up to 200MiB.
+
+And using `-1` as version in a USK now properly finds version `0`, if
+this is the only existing version.
+
+
+There were a number of Java 21 fixes, including all our tests (thanks
+to Bombe!), and improvement to the github actions (thanks to
+AHOHNMYC).
+
+In addition to that there was a lot of polish. Bert Massop and
+Veniamin Fernandes replaced our homegrown CurrentTimeUTC with modern
+Java options. Alex fixed the pronoun used in strings. Bombe added
+getters for all direct field access in the node. Hiina reduced logging
+level of store warnings so no unneeded backtraces are created for node
+with large stores and Juiceman updated code to use more modern
+structures.
+
+Time-dependence of compressor selection was removed. This caused
+non-determinism for inserts and could cause keys to be
+non-reproducible on systems with faster or slower network.
+
+
+And finally the new [exe signing workflow][] we built to fulfill the
+requirements of SignPath, our new windows installer signing provider
+for the upcoming releases, runs the [verify-build script][] on every
+release to ensure that the jar we release has actually been built from
+the sources. This provides a second safety net, in addition to
+anonymous users running the script and posting the results (thanks to
+all who did this — please keep it up, otherwise people have to fully
+trust github). The release is not yet byte-by-byte reproducible,
+because the jar MANIFEST defines among other info the exact java
+version used to compile it, and the java version available differs by
+distribution and time, so it would get harder over time to verify the
+build.
+
+
+A special thanks goes to Bombe for many careful reviews!
+
+[high-impact-task]: https://github.com/hyphanet/wiki/wiki/High-Impact-tasks
+[Roadmap]: https://github.com/hyphanet/wiki/wiki/Roadmap
+[exe signing workflow]: https://github.com/hyphanet/sign-windows-installer
+[verify-build script]: https://github.com/hyphanet/scripts/blob/master/verify-build
+
+# Full changelog:
+
+
+## high impact tasks
+merge debian package as default build action thanks to DC*/desyncr! This resolves one of our high impact tasks.
+
+## Plugins
+Update KeepAlive to commit 86e47a101f26fd1d3be0437681a043aa4ae3f22c
+Update Sharesite to 0.5.1
+Move UPnP2 to normal plugins. It does not seem broken, but UPnP does
+Move Library plugin to advanced plugins because new users tend to get lost with it
+💄 Add better styling to the plugin list in winterfacey to make it easier to understand at a glance — thanks to Bombe
+🔥 Remove option to load plugins from central server — thanks to Bombe! This was an unnecessary privacy risk, since we’re already bundling essential plugins with the installer, and it made plugin handling harder to understand.
+
+## Bookmarks
+Add high-impact-tasks to bookmarks
+Add generate media site to the default bookmarks
+Add Opennet SeedNodes stats site
+Reorder starting bookmarks: FFS → clean spider → Index of Indexes
+Reorder default software bookmarks by ease of use from fproxy
+Disable activelink for Index of Indexes (workaround, because it fails)
+
+## Optimize networking and transfer layer
+break early when condition is met — thanks to Juiceman
+Check the HashCode before equals. This saves ~20% method-runtime.
+Re-order or’ed MessageFilters so the most likely is checked first
+specialize healing to keys close to the node
+fix healing decision: do not divide 0-1 by MAX_VALUE — thanks to Bombe for the review!
+Reduce recently failed and data not found wait times
+
+## Filters
+CSS: Fix: checked only the first char of the key part of CSS selectors, Add test that would catch too lax filtering.
+CSS: Support pseudo-element checked. This enables limited interactivity via CSS.
+CSS: Support the attribute selectors ^= $= *=, Add tests.
+CSS: Support Combinators > + and ~, add test for ~ and simplify the implementation
+CSS: Support word-wrap: anywhere and CSS selector focus-within.
+HTML: allow summary and details html element. Thanks to naejadu
+HTML: accept , thanks to torusrxxx
+
+## Constants
+Show the noderef in basic-mode: it is now robust enough
+
+## Configuration
+accepting localhost in NodeIPPortDetector and allowBindToLocalhost configurable — thanks to s7r!
+Provide static methods for simpler boolean config creation
+Increase default bandwidth to 160KiB upload, when detection fails
+disable setting for new-load-management (NLM broke nodes)
+add utility to disable a config option, thanks to Bombe
+
+## Misc
+add m3u-player insertion test: is added at end of body
+[CI] Update actions, fix actions cache
+♻️ add and use getters and setters for access to node fields
+Increase max transparent passthrough to 200MiB links in m3u-lists.
+Remove time-dependence of compressor selection. This caused
+non-determinism for inserts and could cause keys to be
+non-reproducible.
+improve date object construction in CurrentTimeUTC.get()
+Support Schema hypha[net] to simplify writing browser extensions that forward hypha://-links to Hyphanet.
+polish: show datastore size warning with GiB suffix
+Remove hash generation to native big integer to reduce dependencies. This had come in when merging an old pull request and added a new dependency without need.
+
+## Polish
+Replace indexOf with .contains()
+Change more string comparisons into .isEmpty() checks
+Capitalize L in literal longs
+Add missing Global flag to GetFailed FCP message. Thanks to oishii and Bombe!
+Fix links to mailing lists and IRC in CONTRIBUTING.md — thanks to Juiceman!
+Deprecated custom datetime handling class CurrentTimeUTC
+replace GregorianCalendar with java.time.OffsetDateTime in CurrentTimeUTC — thanks to Veniamin Fernandes
+Refine ClientRequestSelectorTest, PersistentJobRunnerImplTest, SplitFileFetcherStorageTest, and SplitFileInserterStorageTest — thanks to Veniamin Fernandes
+Change deprecated jcenter() maven repo to mavenCentral() — thanks to Veniamin Fernandes
+Added tests for PebbleUtils — thanks to Bombe!
+🐛 Fix NPE when subsets are not initialized — thanks to Bombe
+reduce logging for too many excluded sub-arrays thanks to Hiina
+fix the flag size of nepal — thanks to Percept0r@NYZkOs7eQ…!
+Switch swiss flag to civil and state ensign — thanks to Percept0r@NY
+
+## Fixes
+Thanks to Bombe all our tests work again on Java 21!
+🐛 Fix JarClassLoader’s ability to work with ServiceLoader — thanks to Bombe!
+gzip: replace test workaround by fixing the output of the compressor — thanks to Bombe for the SingleOffsetReplacingOutputStream!
+fix: invalid max store size showed bytes with GiB suffix
+
+
+Also a special thanks to Bombe for many careful reviews!
+
+
+1497:
+
+- fixed severe path folding vulnerability.
+
1496:
diff --git a/README.md b/README.md
index d1ea80a4c90..47ce5e90aef 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[](https://travis-ci.org/freenet/fred)
+[](https://github.com/hyphanet/fred/actions)
[](https://scan.coverity.com/projects/freenet-fred)
# Freenet
@@ -11,7 +11,7 @@ Fred stands for Freenet REference Daemon.
## Building
-We've included the [Gradle Wrapper](https://docs.gradle.org/3.2/userguide/gradle_wrapper.html) as
+We've included the [Gradle Wrapper](https://docs.gradle.org/8.11/userguide/gradle_wrapper.html) as
recommended by the Gradle project. If you trust the version we've committed you can build
immediately:
@@ -23,7 +23,7 @@ immediately:
> gradlew jar
-We've [configured it](gradle/wrapper/gradle-wrapper.properties) to [verify the checksum](https://docs.gradle.org/3.2/userguide/gradle_wrapper.html#sec:verification)
+We've [configured it](gradle/wrapper/gradle-wrapper.properties) to [verify the checksum](https://docs.gradle.org/8.11/userguide/gradle_wrapper.html#wrapper_checksum_verification)
of the archive it downloads from `https://services.gradle.org`.
### Build with ant
@@ -31,6 +31,16 @@ of the archive it downloads from `https://services.gradle.org`.
$ mkdir -p lib; cd lib && grep -o CHK.* ../dependencies.properties | xargs -P16 -I {} bash -c 'fcpget -v {} "$(echo {} | sed s,^.*/,,)"'
$ ant -propertyfile build.properties -f build-clean.xml -Dtest.skip=true -Dfindbugs.skip=true
+## Building the installers
+
+The installers are built from specialized repositories:
+
+- The GNU/Linux, macOS and *nix installer is built from [hyphanet/java_installer](https://github.com/hyphanet/java_installer).
+- The Windows installer is built from [hyphanet/wininstaller-innosetup](https://github.com/hyphanet/wininstaller-innosetup) and signed with [hyphanet/sign-windows-installer](https://github.com/hyphanet/sign-windows-installer).
+
+Free code signing for the Windows installer is provided by [SignPath.io](https://about.signpath.io/), the certificate by the [SignPath Foundation](https://signpath.org/).
+
+
## Testing
### Run Tests
@@ -51,7 +61,7 @@ To test your version of Freenet, build it with ,./gradlew jar`,
stop your node, replace `freenet.jar` in your
Freenet directory with `build/libs/freenet.jar`, and start your node again.
-To override values set in `build.gradle` put them into [the file](https://docs.gradle.org/3.2/userguide/build_environment.html)
+To override values set in `build.gradle` put them into [the file](https://docs.gradle.org/8.11/userguide/build_environment.html)
`gradle.properties` in the format `variable = value`. For instance:
org.gradle.parallel = true
@@ -67,6 +77,13 @@ To override values set in `build.gradle` put them into [the file](https://docs.g
See our [contributor guidelines](CONTRIBUTING.md).
+### Get in contact
+
+* Ask the [development mailing list](https://www.hyphanet.org/pages/help.html#mailing-lists)
+ or join us in [IRC](https://web.libera.chat/?nick=Rabbit|?#freenet) - `#freenet` on
+ `irc.libera.chat`.
+* You can file problems in the [bug tracker](https://freenet.mantishub.io/my_view_page.php).
+
## Add a new dependency
All dependencies must be available via Freenet, so it must be added to
diff --git a/build.gradle b/build.gradle
index 634dcd89801..6054c6767b7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,10 +1,11 @@
+import java.security.MessageDigest
+
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.9.+'
- classpath files('gradle/gradle-witness.jar')
}
}
@@ -13,14 +14,18 @@ configurations {
compile
}
-apply plugin: 'witness'
apply plugin: 'java'
apply plugin: 'maven-publish'
repositories {
flatDir { dirs uri("${projectDir}/lib") }
- maven { url 'https://mvn.freenetproject.org' }
- jcenter()
+ maven {
+ url 'https://mvn.freenetproject.org'
+ metadataSources {
+ artifact()
+ }
+ }
+ mavenCentral()
}
sourceSets {
@@ -28,7 +33,7 @@ sourceSets {
test.compileClasspath += configurations.provided
}
-def version_buildir = "$projectDir/build/tmp/compileVersion/"
+def version_buildir = file("$projectDir/build/tmp/compileVersion/")
def version_src = 'freenet/node/Version.java'
sourceSets {
@@ -48,15 +53,17 @@ def gitrev
task buildInfo {
try {
def cmd = "git describe --always --abbrev=4 --dirty"
- def proc = cmd.execute()
+ def proc = cmd.execute([], project.rootDir)
gitrev = proc.text.trim()
- } catch (java.io.IOException e) {
+ } catch (IOException ignored) {
gitrev = "@unknown@"
}
}
-sourceCompatibility = 1.8
-targetCompatibility = 1.8
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+}
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
@@ -66,37 +73,38 @@ tasks.withType(Javadoc) {
options.encoding = "UTF-8"
}
-task compileVersion (type: JavaCompile) {
- copy {
- from sourceSets.main.java.srcDirs
- into "${version_buildir}"
- include "${version_src}"
+task generateVersionSource(type: Copy) {
+ dependsOn buildInfo
+ from(sourceSets.main.java.srcDirs) {
+ include version_src
filter {
- String line -> line.replaceAll("@custom@","${gitrev}")
+ String line -> line.replaceAll('@custom@', gitrev)
}
}
+ into version_buildir
+}
+
+task compileVersion (type: JavaCompile) {
+ dependsOn generateVersionSource, compileJava
sourceCompatibility = 1.8
targetCompatibility = 1.8
- source = "${version_buildir}"
- include "${version_src}"
- classpath = files(sourceSets.main.compileClasspath, sourceSets.main.output.classesDir)
- destinationDir = file("${buildDir}/java/version/")
+ source = version_buildir
+ include version_src
+ classpath = files(sourceSets.main.compileClasspath, sourceSets.main.output.classesDirs)
+ destinationDirectory.set(layout.buildDirectory.dir("java/version/").get())
}
-compileVersion.dependsOn buildInfo
-compileVersion.dependsOn compileJava
-processResources.dependsOn compileVersion
-task jar (type: Jar, overwrite: true) {
- from (compileVersion) {
- include 'freenet/node/Version**class'
- }
- from ("${buildDir}/classes/java/main/") {
+task buildJar(type: Jar) {
+ dependsOn compileVersion, processResources
+ from(processResources)
+ from(compileJava.destinationDirectory) {
exclude 'freenet/node/Version.class'
exclude 'freenet/node/Version$1.class'
}
- preserveFileTimestamps = false
+ from(compileVersion.destinationDirectory)
+ preserveFileTimestamps = true
reproducibleFileOrder = true
- duplicatesStrategy = "warn"
+ duplicatesStrategy = DuplicatesStrategy.FAIL
archivesBaseName = "freenet"
manifest {
attributes("Permissions": "all-permissions")
@@ -114,12 +122,14 @@ task jar (type: Jar, overwrite: true) {
], "common")
}
}
-jar.dependsOn processResources
+
+jar.enabled = false
+jar.dependsOn buildJar
def jars = []
gradle.addListener(new TaskExecutionListener() {
void afterExecute(Task task, TaskState state) {
- if(task in AbstractArchiveTask) {
+ if(task in AbstractArchiveTask && task.enabled) {
jars << task.outputs.files.singleFile
}
}
@@ -130,7 +140,7 @@ gradle.addBuildListener(new BuildAdapter() {
void buildFinished(BuildResult result) {
if(jars) {
def hash = {
- File file -> def sha256 = java.security.MessageDigest.getInstance('SHA-256')
+ File file -> def sha256 = MessageDigest.getInstance('SHA-256')
file.eachByte(1024 * 4) { buffer, len -> sha256.update(buffer, 0, len) }
println "SHA-256 of ${file.name}: ${sha256.digest().encodeHex().toString()}"
}
@@ -141,12 +151,12 @@ gradle.addBuildListener(new BuildAdapter() {
})
task copyResourcesToClasses2 {
- inputs.dir sourceSets.main.java.srcDirs
- outputs.dir sourceSets.main.output.classesDir
+ inputs.files sourceSets.main.allSource
+ outputs.dir layout.buildDirectory.dir("classes/java/main/")
doLast {
copy {
- from sourceSets.main.java.srcDirs
- into sourceSets.main.output.classesDir
+ from sourceSets.main.allSource
+ into layout.buildDirectory.dir("classes/java/main/")
include 'freenet/l10n/*properties'
include 'freenet/l10n/iso-*.tab'
include 'freenet/clients/http/staticfiles/**'
@@ -155,23 +165,25 @@ task copyResourcesToClasses2 {
}
copy {
from "${projectDir}/"
- into sourceSets.main.output.classesDir
+ into layout.buildDirectory.dir("classes/java/main/")
include 'dependencies.properties'
}
}
}
processResources.dependsOn copyResourcesToClasses2
+compileVersion.dependsOn copyResourcesToClasses2
task copyTestResourcesToClasses2 {
- inputs.dir sourceSets.test.java.srcDirs
- outputs.dir sourceSets.test.output.classesDir
+ inputs.files sourceSets.test.allSource
+ outputs.dir layout.buildDirectory.dir("classes/java/test/")
doLast {
copy {
- from sourceSets.test.java.srcDirs
- into sourceSets.test.output.classesDir
+ from sourceSets.test.allSource
+ into layout.buildDirectory.dir("classes/java/test/")
include 'freenet/client/filter/*/**'
include 'freenet/crypt/ciphers/rijndael-gladman-test-data/**'
include 'freenet/l10n/*properties'
+ include 'freenet/clients/http/templates/**'
}
}
}
@@ -183,13 +195,14 @@ test {
jvmArgs '--add-opens=java.base/java.lang=ALL-UNNAMED'
jvmArgs '--add-opens=java.base/java.util=ALL-UNNAMED'
jvmArgs '--add-opens=java.base/java.io=ALL-UNNAMED'
+ jvmArgs '--add-opens=java.base/java.util.zip=ALL-UNNAMED'
}
minHeapSize = "128m"
maxHeapSize = "512m"
// no inner class
include 'freenet/**/*Test.class'
exclude 'freenet/**/*$*Test.class'
- workingDir = sourceSets.test.output.classesDir
+ workingDir = layout.buildDirectory.dir("classes/java/test/")
scanForTestClasses = false
systemProperties += [
"test.l10npath_test": "freenet/l10n/",
@@ -226,54 +239,33 @@ publishing {
task copyRuntimeLibs(type: Copy) {
into "${buildDir}/output/"
- from configurations.runtime
+ from configurations.runtimeClasspath
from jar
}
copyRuntimeLibs.dependsOn jar
// In this section you declare the dependencies for your production and test code
dependencies {
- compile "org.bouncycastle:bcprov-jdk15on:1.59"
- compile "net.java.dev.jna:jna:4.5.2"
- compile "net.java.dev.jna:jna-platform:4.5.2"
- compile "org.freenetproject:freenet-ext:29"
- compile "io.pebbletemplates:pebble:3.1.5"
+ implementation "org.bouncycastle:bcprov-jdk15on:1.59"
+ implementation "net.java.dev.jna:jna:4.5.2"
+ implementation "net.java.dev.jna:jna-platform:4.5.2"
+ implementation "org.freenetproject:freenet-ext:29"
+ implementation "io.pebbletemplates:pebble:3.1.5"
// dependencies of pebble
- compile "org.unbescape:unbescape:1.1.6.RELEASE"
- compile "org.slf4j:slf4j-api:1.7.25"
-
- testCompile 'junit:junit:4.12'
- testCompile "org.mockito:mockito-core:1.9.5"
- testCompile "org.hamcrest:hamcrest-library:1.3"
- testCompile "org.hamcrest:hamcrest-core:1.3"
- testCompile "org.objenesis:objenesis:1.0"
-}
+ implementation "org.unbescape:unbescape:1.1.6.RELEASE"
+ implementation "org.slf4j:slf4j-api:1.7.25"
-dependencyVerification {
- // testCompile includes all of compile deps... so let's include only these
- includedConfigurations = [configurations.testCompile]
- verify = [
- 'org.bouncycastle:bcprov-jdk15on:1c31e44e331d25e46d293b3e8ee2d07028a67db011e74cb2443285aed1d59c85',
- 'net.java.dev.jna:jna-platform:f1d00c167d8921c6e23c626ef9f1c3ae0be473c95c68ffa012bc7ae55a87e2d6',
- 'net.java.dev.jna:jna:0c8eb7acf67261656d79005191debaba3b6bf5dd60a43735a245429381dbecff',
- 'org.freenetproject:freenet-ext:32f2b3d6beedf54137ea2f9a3ebef67666d769f0966b08cd17fd7db59ba4d79f',
- 'junit:junit:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
- 'org.mockito:mockito-core:f97483ba0944b9fa133aa29638764ddbeadb51ec3dbc02074c58fa2caecd07fa',
- 'org.hamcrest:hamcrest-library:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
- 'org.hamcrest:hamcrest-core:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
- 'org.objenesis:objenesis:c5694b55d92527479382f254199b3c6b1d8780f652ad61e9ca59919887f491a8',
- 'io.pebbletemplates:pebble:d253a6dde59e138698aaaaee546461d2f1f6c8bd2aa38ecdd347df17cf90d6f0',
- // dependencies of pebble
- 'org.unbescape:unbescape:597cf87d5b1a4f385b9d1cec974b7b483abb3ee85fc5b3f8b62af8e4bec95c2c',
- 'org.slf4j:slf4j-api:18c4a0095d5c1da6b817592e767bb23d29dd2f560ad74df75ff3961dbde25b79'
- ]
+ testImplementation 'junit:junit:4.13.2'
+ testImplementation "org.mockito:mockito-core:1.9.5"
+ testImplementation "org.hamcrest:hamcrest:3.0"
+ testImplementation "org.objenesis:objenesis:1.0"
}
task tar(type: Tar) {
description = "Build a source release, specifically excluding the build directories and gradle wrapper files"
compression = Compression.BZIP2
- baseName = "freenet-sources"
+ archiveBaseName = "freenet-sources"
from(project.rootDir) {
exclude '**/build'
@@ -281,20 +273,22 @@ task tar(type: Tar) {
exclude '.gradle'
}
- into(baseName)
+ into(archiveBaseName)
- preserveFileTimestamps = false
+ preserveFileTimestamps = true
reproducibleFileOrder = true
// Set destination directory.
- destinationDir = file("${project.buildDir}")
+ destinationDirectory = file("${project.buildDir}")
- archiveName = "${baseName}.tgz"
+ archiveFileName = "${archiveBaseName}.tgz"
doLast { // generate md5 checksum
- ant.checksum file:"$destinationDir/$archiveName"
+ ant.checksum file:"$destinationDirectory/$archiveFileName"
}
}
-javadoc << {
- failOnError false
+javadoc {
+ doLast {
+ failOnError false
+ }
}
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 00000000000..947e77471bf
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,54 @@
+freenet (0.7.5+1498-1) unstable; urgency=medium
+
+ * Build 1498
+
+ -- Arne Sun, 15 Oct 2023 23:42:30 +0100
+
+freenet (0.7.5+1497-1) unstable; urgency=medium
+
+ * Build 1497
+
+ -- Arne Thu, 07 Sep 2023 23:42:30 +0100
+
+freenet (0.7.5+1494-7) unstable; urgency=medium
+
+ * Remove outdated files
+
+ -- DC Sat, 17 Sep 2022 15:46:23 +0100
+
+freenet (0.7.5+1494-7) unstable; urgency=medium
+
+ * Lintian binary overrides
+
+ -- DC Sat, 17 Sep 2022 13:57:51 +0100
+
+freenet (0.7.5+1494-4) unstable; urgency=medium
+
+ * Update package build descriptions
+
+ -- DC Sat, 02 Jul 2022 00:36:27 +0100
+
+freenet (0.7.5+1494-3) unstable; urgency=medium
+
+ * Add attribution to original work
+
+ -- DC* Sat, 02 Jul 2022 00:26:57 +0100
+
+freenet (0.7.5+1494-2) unstable; urgency=medium
+
+ * Update maintainer
+
+ -- DC* Sat, 02 Jul 2022 00:19:27 +0100
+
+freenet (0.7.5+1494-1) unstable; urgency=medium
+
+ * Build 1494
+
+ -- DC* Sat, 02 Jul 2022 00:00:49 +0100
+
+freenet (0.7.5+1493-1) unstable; urgency=medium
+
+ * Initial Release.
+ Packaged originally by Ximin Luo : https://github.com/freenet/debian
+
+ -- DC* Fri, 01 Jul 2022 23:25:13 +0100
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 00000000000..b4de3947675
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+11
diff --git a/debian/control b/debian/control
new file mode 100644
index 00000000000..b644ffd9e6f
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,28 @@
+Source: freenet
+Section: net
+Priority: optional
+Maintainer: DC*
+Build-Depends: debhelper (>= 9), javahelper, quilt, adduser (>= 3.11),
+ git-core, default-jdk, wget, service-wrapper, git-buildpackage
+Standards-Version: 4.5.1
+Homepage: http://freenetproject.org/
+
+Package: freenet
+Architecture: any
+Depends: adduser, procps, gettext, default-jre-headless, libservice-wrapper-java, service-wrapper,
+ ${shlibs:Depends}, ${misc:Depends}, ${java:Depends}
+Replaces: fred
+Conflicts: fred
+Tag: interface::daemon, network::server
+Description: Lets you anonymously share files, browse and publish "freesites" (web
+ sites accessible only through Freenet) and chat on forums, without fear of
+ censorship. Freenet is decentralised to make it less vulnerable to attack, and
+ if used in "darknet" mode, where users only connect to their friends, is very
+ difficult to detect. Communications by Freenet nodes are encrypted and are
+ routed through other nodes to make it extremely difficult to determine who is
+ requesting the information and what its content is.
+ .
+ This package contains the Freenet REference Daemon (fred), which provides low
+ level access to data stored on Freenet, and a web proxy for viewing freesites.
+ Note that fred creates a datastore of at least 256 MB on first startup.
+ .
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 00000000000..d1b2a11acd1
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,203 @@
+This package was debianized by:
+
+ Masayuki Hatta (mhatta) on Fri, 10 Jul 2009 13:48:38 +0900
+
+It was downloaded from:
+
+ http://freenetproject.org/developer.html
+
+Upstream Author:
+
+ The Freenet Project
+
+Copyright:
+
+ Copyright (C) 2009 The Freenet Project
+
+License:
+
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Note that a large portion of Freenet is distributed under GPL2 *or
+ later*.
+
+On Debian systems, the complete text of the GNU General
+Public License version 2 can be found in `/usr/share/common-licenses/GPL-2'.
+
+The Debian packaging is:
+
+ Copyright (C) 2009 Masayuki Hatta (mhatta)
+
+and is licensed under the GPL version 3,
+see `/usr/share/common-licenses/GPL-3'.
+
+This distribution contains several portions which bear licenses
+different from GPL2:
+
+Mantissa:
+
+Copyright (c) 2001-2004, Luc Maisonobe All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ Redistributions of source code must retain the
+ above copyright notice, this list of conditions and
+ the following disclaimer.
+
+ Redistributions in binary form must reproduce the
+ above copyright notice, this list of conditions and
+ the following disclaimer in the documentation
+ and/or other materials provided with the
+ distribution.
+
+ Neither the names of spaceroots.org, spaceroots.com
+ nor the names of their contributors may be used to
+ endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+contrib/bdb:
+
+The following is the license that applies to this copy of the Berkeley
+DB Java Edition software. For a license to use the Berkeley DB Java
+Edition software under conditions other than those described here, or
+to purchase support for this software, please contact Oracle at
+berkeleydb-info_us@oracle.com.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+/*
+ * Copyright (c) 2002,2008 Oracle. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Redistributions in any form must be accompanied by information on
+ * how to obtain complete source code for the DB software and any
+ * accompanying software that uses the DB software. The source code
+ * must either be included in the distribution or be available for no
+ * more than the cost of distribution plus a nominal fee, and must be
+ * freely redistributable under reasonable conditions. For an
+ * executable file, complete source code means the source code for all
+ * modules it contains. It does not include source code for modules or
+ * files that typically accompany the major components of the operating
+ * system on which the executable file runs.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ORACLE ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL ORACLE BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2005 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+contrib/fec:
+
+/*
+ * Java Forward Error Correction Library
+ * Copyright (C) 2001 Onion Networks
+ * Copyright (C) 2000 OpenCola
+ *
+ * Portions derived from code by Luigi Rizzo:
+ * fec.c -- forward error correction based on Vandermonde matrices
+ * 980624
+ * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
+ *
+ * Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
+ * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
+ * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+contrib/java/net/contrapuctus/lzma:
+
+// Copyright (c)2008 Christopher League
+
+// This is free software, but it comes with ABSOLUTELY NO WARRANTY.
+// GNU Lesser General Public License 2.1 or Common Public License 1.0
diff --git a/debian/files b/debian/files
new file mode 100644
index 00000000000..412595d9430
--- /dev/null
+++ b/debian/files
@@ -0,0 +1,2 @@
+freenet_0.7.5+1498-1_amd64.buildinfo net optional
+freenet_0.7.5+1498-1_amd64.deb net optional
diff --git a/debian/freenet.default b/debian/freenet.default
new file mode 100644
index 00000000000..5c71cf728f6
--- /dev/null
+++ b/debian/freenet.default
@@ -0,0 +1,13 @@
+# Defaults for freenet-daemon initscript
+# sourced by /etc/init.d/freenet-daemon
+# installed at /etc/default/freenet-daemon by the maintainer scripts
+
+#
+# This is a POSIX shell fragment
+#
+
+# Do you really want to run freenet-daemon(fred)?
+RUN=yes
+
+# Nice level
+NICE=10
diff --git a/debian/freenet.dirs b/debian/freenet.dirs
new file mode 100644
index 00000000000..4cfe7dec582
--- /dev/null
+++ b/debian/freenet.dirs
@@ -0,0 +1,5 @@
+etc/freenet/noderef
+usr/share/java
+usr/share/freenet
+var/log/freenet
+var/lib/freenet
diff --git a/debian/freenet.docs b/debian/freenet.docs
new file mode 100644
index 00000000000..0b6e0f3219b
--- /dev/null
+++ b/debian/freenet.docs
@@ -0,0 +1,2 @@
+AUTHORS
+README.md
diff --git a/debian/freenet.ini b/debian/freenet.ini
new file mode 100644
index 00000000000..3f6aaa604a5
--- /dev/null
+++ b/debian/freenet.ini
@@ -0,0 +1,14 @@
+node.install.nodeDir=/etc/freenet/noderef
+node.install.cfgDir=/etc/freenet
+node.install.userDir=/var/lib/freenet/state
+node.install.runDir=/var/run/freenet
+node.install.storeDir=/var/lib/freenet/store
+node.install.pluginDir=/var/lib/freenet/plugins
+node.install.tempDir=/tmp/freenet
+node.downloadsDir=/var/lib/freenet/complete
+logger.dirname=/var/log/freenet
+logger.priority=NORMAL
+node.updater.enabled=false
+node.updater.autoupdate=false
+node.updater.updateInstallers=false
+End
diff --git a/debian/freenet.init b/debian/freenet.init
new file mode 100644
index 00000000000..985a6c36f37
--- /dev/null
+++ b/debian/freenet.init
@@ -0,0 +1,243 @@
+#! /bin/sh
+
+#
+# Copyright (c) 1999, 2022 Tanuki Software, Ltd.
+# http://www.tanukisoftware.com
+# All rights reserved.
+#
+# This software is the proprietary information of Tanuki Software.
+# You shall use it only in accordance with the terms of the
+# license agreement you entered into with Tanuki Software.
+# http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html
+#
+# Java Service Wrapper sh script. Suitable for starting and stopping
+# wrapped Java applications on UNIX platforms.
+# Optimized for use with version 3.5.51 of the Wrapper.
+#
+
+#-----------------------------------------------------------------------------
+# These settings can be modified to fit the needs of your application
+
+# IMPORTANT - Please always stop and uninstall an application before making
+# any changes to this file. Failure to do so could remove the
+# script's ability to control the application.
+
+# NOTE - After loading the variables below, the script will attempt to locate a
+# file with the same basename as this script and having a '.shconf' extension.
+# If such file exists, it will be executed giving the user a chance to
+# override the default settings. Having the customized configuration in a
+# separate '.shconf' file makes it easier to upgrade the Wrapper, as the
+# present script file can then be replaced with minimal changes (although at
+# least the 'INIT INFO' below needs to be updated).
+
+# Initialization block for the install_initd and remove_initd scripts used by
+# SUSE linux, CentOS and RHEL distributions. Also used by update-rc.d.
+# Note: From CentOS 6, make sure the BEGIN INIT INFO section is before any line
+# of code otherwise the service won't be displayed in the Service
+# Configuration GUI.
+### BEGIN INIT INFO
+# Provides: freenet
+# Required-Start: $remote_fs $syslog
+# Should-Start: $network $time
+# Should-Stop: $network $time
+# Required-Stop: $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Freenet 0.7.5 build 1498 (experimental release)
+# Description: Freenet reference daemon
+### END INIT INFO
+
+# Application name and long name: If these variables are not set (or left to
+# the default tokens), APP_NAME will default to the name of the script, then
+# APP_LONG_NAME will default to the value of APP_NAME.
+APP_NAME="freenet"
+APP_LONG_NAME="Freenet 0.7.5 build 1498 (experimental release)"
+
+# If uncommented (and set to false), APP_NAME and APP_LONG_NAME will no longer
+# be passed to the wrapper. See documentation for details.
+#APP_NAME_PASS_TO_WRAPPER=false
+
+# Wrapper
+WRAPPER_CMD="/usr/sbin/wrapper"
+WRAPPER_CONF="/etc/freenet/wrapper.conf"
+
+# Priority at which to run the wrapper. See "man nice" for valid priorities.
+# nice is only used if a priority is specified.
+PRIORITY="10"
+
+# Location of the pid file.
+PIDDIR="/var/run/freenet"
+
+# PIDFILE_CHECK_PID tells the script to double check whether the pid in the pid
+# file actually exists and belongs to this application. When not set, only
+# check the pid, but not what it is. This is only needed when multiple
+# applications need to share the same pid file.
+PIDFILE_CHECK_PID=true
+
+# FIXED_COMMAND tells the script to use a hard coded action rather than
+# expecting the first parameter of the command line to be the command.
+# By default the command will be expected to be the first parameter.
+#FIXED_COMMAND=console
+
+# PASS_THROUGH controls how the script arguments should be passed to the
+# Wrapper. Possible values are:
+# - commented or 'false': the arguments will be ignored (not passed).
+# - 'app_args' or 'true': the arguments will be passed through the Wrapper as
+# arguments for the Java Application.
+# - 'both': both Wrapper properties and Application arguments can be passed to
+# the Wrapper. The Wrapper properties come in first position. The
+# user can optionally add a '--' separator followed by application
+# arguments.
+# NOTE - If FIXED_COMMAND is set to true the above applies to all arguments,
+# otherwise it applies to arguments starting with the second.
+# NOTE - Passing arguments is only valid with the following commands:
+# - 'console'
+# - 'start', 'restart', 'condrestart' (if not installed as a daemon)
+#PASS_THROUGH=app_args
+
+# If uncommented, causes the Wrapper to be shutdown using an anchor file.
+# When launched with the 'start' command, it will also ignore all INT and
+# TERM signals.
+#IGNORE_SIGNALS=true
+
+# Wrapper will start the JVM asynchronously. Your application may have some
+# initialization tasks and it may be desirable to wait a few seconds
+# before returning. For example, to delay the invocation of following
+# startup scripts. Setting WAIT_AFTER_STARTUP to a positive number will
+# cause the start command to delay for the indicated period of time
+# (in seconds).
+WAIT_AFTER_STARTUP=0
+
+# If set, wait for the wrapper to report that the daemon has started
+WAIT_FOR_STARTED_STATUS=true
+WAIT_FOR_STARTED_TIMEOUT=120
+
+# If set, the status, start_msg and stop_msg commands will print out detailed
+# state information on the Wrapper and Java processes.
+#DETAIL_STATUS=true
+
+# If set, the 'pause' and 'resume' commands will be enabled. These make it
+# possible to pause the JVM or Java application without completely stopping
+# the Wrapper. See the wrapper.pausable and wrapper.pausable.stop_jvm
+# properties for more information.
+#PAUSABLE=true
+
+# Set the mode used to 'pause' or 'resume' the Wrapper. Possible values are
+# 'signals' which uses SIGUSR1 and SIGUSR2, and 'file' which uses the command
+# file to communicate these actions. The default value is 'signals'.
+# Be aware that depending on the mode, the properties wrapper.signal.mode.usr1,
+# wrapper.signal.mode.usr2, or wrapper.commandfile of the configuration file may
+# be overriden.
+#PAUSABLE_MODE=signals
+
+# If set, the Wrapper will be run as the specified user.
+# IMPORTANT - Make sure that the user has the required privileges to write
+# the PID file and wrapper.log files. Failure to be able to write the log
+# file will cause the Wrapper to exit without any way to write out an error
+# message.
+# NOTES - This will set the user which is used to run the Wrapper as well as
+# the JVM and is not useful in situations where a privileged resource or
+# port needs to be allocated prior to the user being changed.
+# - Setting this variable will cause stdin to be closed. While this
+# should not be a problem when running as Daemon, it would disable ability
+# for console applications to receive inputs.
+RUN_AS_USER="freenet"
+
+# When RUN_AS_USER is set, the 'runuser' command will be used to substitute the
+# user. If not present on the machine, 'su' will be used as a fallback.
+# The parameter below lets you specify option(s) for the 'runuser' (or 'su')
+# command.
+# NOTES - The '-u' option is not allowed. Please set the user with RUN_AS_USER.
+# - On GNU/Linux systems, if the user specified by RUN_AS_USER doesn't
+# have a default shell please specify one with the '-s' option.
+#SU_OPTS="-s /bin/bash"
+
+# By default we show a detailed usage block. Uncomment to show brief usage.
+#BRIEF_USAGE=true
+
+# Set which service management tool to use.
+# Possible values are:
+# for linux...: auto, systemd, upstart, initd
+# for aix.....: auto, src, initd
+# When set to 'auto', this script file will try to detect in the order of the
+# list for each platform which service management tool to use to install the Wrapper.
+SERVICE_MANAGEMENT_TOOL=auto
+
+# Specify how the Wrapper daemon and its child processes should be killed
+# when using systemd.
+# The default is 'control-group' which tells systemd to kill all child
+# processes (including detached ones) in the control group of the daemon
+# when it stops.
+# Alternatively, 'process' can be specified to prevent systemd from
+# killing the child processes leaving this responsibility to the Wrapper.
+# In this case child processes marked as 'detached' will not be killed on shutdown.
+# NOTE - the daemon must be reinstalled for any changes on this property to take effect.
+SYSTEMD_KILLMODE=control-group
+
+# When installing on Mac OSX platforms, the following domain will be used to
+# prefix the plist file name.
+PLIST_DOMAIN=org.tanukisoftware.wrapper
+
+# When installing on Mac OSX platforms, this parameter controls whether the daemon
+# is to be kept continuously running or to let demand and conditions control the
+# invocation.
+MACOSX_KEEP_RUNNING="false"
+
+# The following two lines are used by the chkconfig command. Change as is
+# appropriate for your application. They should remain commented.
+# chkconfig: 2345 20 80
+# description: Freenet 0.7.5 build 1498 (experimental release)
+
+# Set run level to use when installing the application to start and stop on
+# system startup and shutdown. It is important that the application always
+# be uninstalled before making any changes to the run levels.
+# It is also possible to specify different run levels based on the individual
+# platform. When doing so this script will look for defined run levels in
+# the following order:
+# 1) "RUN_LEVEL_S_$DIST_OS" or "RUN_LEVEL_K_$DIST_OS", where "$DIST_OS" is
+# the value of DIST_OS. "RUN_LEVEL_S_solaris=20" for example.
+# 2) RUN_LEVEL_S or RUN_LEVEL_K, to specify specify start or stop run levels.
+# 3) RUN_LEVEL, to specify a general run level.
+RUN_LEVEL=20
+
+# List of files to source prior to executing any commands. Use ';' as delimiter.
+# For example:
+# FILES_TO_SOURCE="/home/user/.bashrc;anotherfile;../file3"
+FILES_TO_SOURCE=
+
+# Do not modify anything beyond this point
+#-----------------------------------------------------------------------------
+
+if [ -f "/etc/default/$APP_NAME" ]; then
+ . "/etc/default/$APP_NAME"
+fi
+
+# WRAPPER_PREINIT START
+# do we want to run at all?
+
+if [ "$RUN" != "yes" ]; then echo >&2 "RUN is not yes; abort"; exit 1; fi
+
+# set PRIORITY from /etc/default
+
+if [ -n "$NICE" ]; then PRIORITY="$NICE"; fi
+
+# copy default config files, if necessary
+
+ensure_exists() { if [ ! -f "$1" ]; then cp "$2" "$1"; fi; }
+
+ensure_exists /etc/freenet/wrapper.conf /usr/share/freenet/wrapper.conf
+ensure_exists /etc/freenet/freenet.ini /usr/share/freenet/freenet.ini
+ensure_exists /etc/freenet/noderef/seednodes.fref /usr/share/freenet/seednodes.fref
+
+[ -z "$SERVER_USER" ] && SERVER_USER=freenet
+[ -z "$SERVER_GROUP" ] && SERVER_GROUP=freenet
+
+if [ ! -d "$PIDDIR" ]; then
+ mkdir "$PIDDIR" || exit 1
+ chown $SERVER_USER:$SERVER_GROUP "$PIDDIR" || exit 1
+ chmod 2750 "$PIDDIR" || exit 1
+fi
+# WRAPPER_PREINIT END
+
+. "/usr/share/wrapper/daemon.sh"
+
diff --git a/debian/freenet.install b/debian/freenet.install
new file mode 100644
index 00000000000..a53d3cfdbf5
--- /dev/null
+++ b/debian/freenet.install
@@ -0,0 +1,3 @@
+debian/seednodes.fref usr/share/freenet
+debian/freenet.ini usr/share/freenet
+debian/wrapper.conf usr/share/freenet
diff --git a/debian/freenet.lintian-overrides b/debian/freenet.lintian-overrides
new file mode 100644
index 00000000000..8b68d74645d
--- /dev/null
+++ b/debian/freenet.lintian-overrides
@@ -0,0 +1,4 @@
+freenet: init.d-script-does-not-implement-required-option etc/init.d/freenet force-reload
+freenet: init.d-script-does-not-implement-required-option etc/init.d/freenet restart
+freenet: init.d-script-does-not-implement-required-option etc/init.d/freenet start
+freenet: init.d-script-does-not-implement-required-option etc/init.d/freenet stop
diff --git a/debian/freenet.postint b/debian/freenet.postint
new file mode 100644
index 00000000000..f8ed7b7bd93
--- /dev/null
+++ b/debian/freenet.postint
@@ -0,0 +1,59 @@
+#!/bin/sh
+# postinst script for freenet
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * `configure'
+# * `abort-upgrade'
+# * `abort-remove' `in-favour'
+#
+# * `abort-remove'
+# * `abort-deconfigure' `in-favour'
+# `removing'
+#
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+ configure)
+
+ # If the package has default file it could be sourced, so that
+ # the local $SERVER_GROUPin can overwrite the defaults
+
+ [ -f "/etc/default/freenet" ] && . /etc/default/freenet
+
+ # Sane defaults:
+
+ [ -z "$SERVER_USER" ] && SERVER_USER=freenet
+ [ -z "$SERVER_GROUP" ] && SERVER_GROP=freenet
+
+ # Make sure that all existing processes are stopped
+ PID=$(ps -eo pid,user|grep freenet|cut -d ' ' -f 2)
+ kill -s KILL ${PID} > /dev/null 2>&1 || true
+
+ # Set file and directory permissions
+ chown root:$SERVER_USER /etc/freenet /etc/freenet/noderef
+ chmod 2775 /etc/freenet /etc/freenet/noderef
+ chown $SERVER_USER:$SERVER_GROUP /var/log/freenet
+ chmod 2750 /var/log/freenet
+ ;;
+
+ abort-upgrade|abort-remove|abort-deconfigure)
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/freenet.postrm b/debian/freenet.postrm
new file mode 100644
index 00000000000..413521e0c5a
--- /dev/null
+++ b/debian/freenet.postrm
@@ -0,0 +1,84 @@
+#!/bin/sh
+# postrm script for freenet
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * `remove'
+# * `purge'
+# * `upgrade'
+# * `failed-upgrade'
+# * `abort-install'
+# * `abort-install'
+# * `abort-upgrade'
+# * `disappear'
+#
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+ purge)
+ # find first and last SYSTEM_UID numbers
+ for LINE in `grep SYSTEM_UID /etc/adduser.conf | grep -v "^#"`; do
+ case $LINE in
+ FIRST_SYSTEM_UID*)
+ FIRST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='`
+ ;;
+ LAST_SYSTEM_UID*)
+ LAST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='`
+ ;;
+ *)
+ ;;
+ esac
+ done
+ # Remove system account if necessary
+ CREATEDUSER="freenet"
+ DIETIME=10 # Time to wait for the server to die
+ if [ -n "$FIRST_SYSTEM_UID" ] && [ -n "$LAST_SYSTEM_UID" ]; then
+ if USERID=`getent passwd $CREATEDUSER | cut -f 3 -d ':'`; then
+ if [ -n "$USERID" ]; then
+ if [ "$FIRST_SYSTEM_UID" -le "$USERID" ] && \
+ [ "$USERID" -le "$LAST_SYSTEM_UID" ]; then
+ echo -n "Removing $CREATEDUSER system user.."
+ sleep "$DIETIME"s
+ deluser --quiet --remove-home $CREATEDUSER || true
+ echo "..done"
+ fi
+ fi
+ fi
+ fi
+ # Remove system group if necessary
+ CREATEDGROUP=freenet
+ FIRST_USER_GID=`grep ^USERS_GID /etc/adduser.conf | cut -f2 -d '='`
+ if [ -n "$FIRST_USER_GID" ]; then
+ if GROUPGID=`getent group $CREATEDGROUP | cut -f 3 -d ':'`; then
+ if [ -n "$GROUPGID" ]; then
+ if [ "$FIRST_USER_GID" -gt "$GROUPGID" ]; then
+ echo -n "Removing $CREATEDGROUP group.."
+ delgroup --only-if-empty $CREATEDGROUP || true
+ echo "..done"
+ fi
+ fi
+ fi
+ fi
+ rm -rf /var/lib/freenet
+ ;;
+
+ remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+ ;;
+
+ *)
+ echo "postrm called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/freenet.preinst b/debian/freenet.preinst
new file mode 100644
index 00000000000..a1a8cd132f6
--- /dev/null
+++ b/debian/freenet.preinst
@@ -0,0 +1,100 @@
+#!/bin/sh
+# preinst script for freenet
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * `install'
+# * `install'
+# * `upgrade'
+# * `abort-upgrade'
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+ install|upgrade)
+ # If the package has default file it could be sourced, so that
+ # the local $SERVER_GROUPin can overwrite the defaults
+
+ [ -f "/etc/default/freenet" ] && . /etc/default/freenet
+
+ # Sane defaults:
+
+ [ -z "$SERVER_HOME" ] && SERVER_HOME="/var/lib/freenet"
+ [ -z "$SERVER_USER" ] && SERVER_USER=freenet
+ [ -z "$SERVER_GROUP" ] && SERVER_GROUP=freenet
+ [ -z "$SERVER_NAME" ] && SERVER_NAME="Freenet REference Daemon"
+ [ -z "$SERVER_LOG" ] && SERVER_LOG="/var/log/freenet"
+ [ -z "$SERVER_ETC" ] && SERVER_ETC="/etc/freenet"
+
+ # Groups that the user will be added to, if undefined, then none.
+ ADDGROUP="freenet"
+
+ # create user to avoid running server as root
+ # 1. create group if not existing
+ if ! getent group | grep -q "^$SERVER_GROUP:" ; then
+ echo -n "Adding group $SERVER_GROUP.."
+ addgroup --quiet --system $SERVER_GROUP 2>/dev/null ||true
+ echo "..done"
+ fi
+ # 2. create homedir if not existing
+ test -d $SERVER_HOME || mkdir $SERVER_HOME
+ test -d $SERVER_LOG || mkdir $SERVER_LOG
+ test -d $SERVER_ETC || mkdir $SERVER_ETC
+ # 3. create user if not existing
+ if ! getent passwd | grep -q "^$SERVER_USER:"; then
+ echo -n "Adding system user $SERVER_USER.."
+ adduser --quiet \
+ --system \
+ --shell /bin/sh \
+ --ingroup $SERVER_GROUP \
+ --no-create-home \
+ --home /nonexistent \
+ --disabled-password \
+ $SERVER_USER 2>/dev/null || true
+ echo "..done"
+ fi
+ # 4. adjust passwd entry
+ usermod -c "$SERVER_NAME" \
+ -d $SERVER_HOME \
+ -g $SERVER_GROUP \
+ $SERVER_USER
+ # 5. adjust file and directory permissions
+ if ! dpkg-statoverride --list $SERVER_HOME >/dev/null
+ then
+ chown -f $SERVER_USER:$SERVER_GROUP $SERVER_HOME
+ chmod -f u=rwx,g=rxs,o= $SERVER_HOME
+ chown -f $SERVER_USER:$SERVER_GROUP $SERVER_LOG
+ chmod -f u=rwx,g=rxs,o= $SERVER_LOG
+ chown -f $SERVER_USER:$SERVER_GROUP $SERVER_ETC
+ chmod -f u=rwx,g=rxs,o= $SERVER_ETC
+
+ fi
+ # 6. Add the user to the ADDGROUP group
+ if test -n $ADDGROUP
+ then
+ if ! groups $SERVER_USER | cut -d: -f2 | \
+ grep -qw $ADDGROUP; then
+ adduser $SERVER_USER $ADDGROUP
+ fi
+ fi
+ ;;
+
+ abort-upgrade)
+ ;;
+
+ *)
+ echo "preinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/freenet.service.params b/debian/freenet.service.params
new file mode 100644
index 00000000000..9dd4cae297d
--- /dev/null
+++ b/debian/freenet.service.params
@@ -0,0 +1,32 @@
+freenet
+Freenet @version@ build @build@ (experimental release)
+Freenet reference daemon
+WRAPPER_CONF /etc/freenet/wrapper.conf
+PRIORITY 10
+RUN_AS_USER freenet
+PIDDIR /var/run/freenet
+
+# do we want to run at all?
+
+if [ "$RUN" != "yes" ]; then echo >&2 "RUN is not yes; abort"; exit 1; fi
+
+# set PRIORITY from /etc/default
+
+if [ -n "$NICE" ]; then PRIORITY="$NICE"; fi
+
+# copy default config files, if necessary
+
+ensure_exists() { if [ ! -f "$1" ]; then cp "$2" "$1"; fi; }
+
+ensure_exists /etc/freenet/wrapper.conf /usr/share/freenet/wrapper.conf
+ensure_exists /etc/freenet/freenet.ini /usr/share/freenet/freenet.ini
+ensure_exists /etc/freenet/noderef/seednodes.fref /usr/share/freenet/seednodes.fref
+
+[ -z "$SERVER_USER" ] && SERVER_USER=freenet
+[ -z "$SERVER_GROUP" ] && SERVER_GROUP=freenet
+
+if [ ! -d "$PIDDIR" ]; then
+ mkdir "$PIDDIR" || exit 1
+ chown $SERVER_USER:$SERVER_GROUP "$PIDDIR" || exit 1
+ chmod 2750 "$PIDDIR" || exit 1
+fi
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 00000000000..60026f8d707
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,59 @@
+#!/usr/bin/env -S make -f
+# -*- makefile -*-
+
+# Uncomment this to turn on verbose mode.
+export DH_VERBOSE=0
+FREENET_VERSION := 0.7.5
+FREENET_BUILD := 1498
+WRAPPER_INIT := /usr/share/wrapper/make-wrapper-init.sh
+
+BUILD_DIR := /tmp/fred-build
+
+REFS := https://github.com/freenet/seedrefs/archive/refs/heads/master.zip
+REFS_NAME := seedrefs-master
+REFS_DIR := $(BUILD_DIR)/seeds
+
+export GRADLE_OPTS := -Dorg.gradle.daemon=true -Xmx512m -Dorg.gradle.project.buildDir=$(BUILD_DIR)
+export GRADLE_USER_HOME := $(BUILD_DIR)/gradle
+
+%:
+ dh $@ --with javahelper
+
+$(REFS_DIR):
+ mkdir -p $(REFS_DIR)
+ wget -q $(REFS) -O $(REFS_DIR)/$(REFS_NAME).zip
+ unzip $(REFS_DIR)/$(REFS_NAME).zip -d $(REFS_DIR)
+
+build_seed_file: $(REFS_DIR)
+ cat $(REFS_DIR)/$(REFS_NAME)/* > debian/seednodes.fref
+
+clean:
+ rm -f debian/seednodes.fref
+ rm -rf .gradle gradle/wrapper/dists debian/freenet
+
+override_dh_auto_build: build_seed_file
+ ./gradlew jar; \
+ ./gradlew copyRuntimeLibs
+
+ sed -e 's/@version@/$(FREENET_VERSION)/' -e 's/@build@/$(FREENET_BUILD)/' $(CURDIR)/debian/freenet.service.params | \
+ $(WRAPPER_INIT) -q > "$(CURDIR)/debian/freenet.init"
+
+# override_dh_builddeb:
+# dh_builddeb -- -Zgzip
+
+override_dh_auto_install:
+ dh_auto_install
+ jh_installlibs $(BUILD_DIR)/libs/freenet.jar
+
+override_dh_auto_test:
+
+override_jh_depends:
+
+override_jh_installlibs:
+ jh_installlibs $(BUILD_DIR)/output/freenet-ext-29.jar
+ jh_installlibs $(BUILD_DIR)/output/jna-4.5.2.jar
+ jh_installlibs $(BUILD_DIR)/output/jna-platform-4.5.2.jar
+ jh_installlibs $(BUILD_DIR)/output/bcprov-jdk15on-1.59.jar
+ jh_installlibs $(BUILD_DIR)/output/pebble-3.1.5.jar
+ jh_installlibs $(BUILD_DIR)/output/unbescape-1.1.6.RELEASE.jar
+ jh_installlibs $(BUILD_DIR)/output/slf4j-api-1.7.25.jar
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 00000000000..163aaf8d82b
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides
new file mode 100644
index 00000000000..763f2e44a15
--- /dev/null
+++ b/debian/source/lintian-overrides
@@ -0,0 +1,5 @@
+freenet source: source-is-missing src/freenet/clients/http/staticfiles/freenetjs/*
+freenet: init.d-script-does-not-implement-required-option etc/init.d/freenet force-reload
+freenet: init.d-script-does-not-implement-required-option etc/init.d/freenet restart
+freenet: init.d-script-does-not-implement-required-option etc/init.d/freenet start
+freenet: init.d-script-does-not-implement-required-option etc/init.d/freenet stop
diff --git a/debian/wrapper.conf b/debian/wrapper.conf
new file mode 100644
index 00000000000..c3332b34ab9
--- /dev/null
+++ b/debian/wrapper.conf
@@ -0,0 +1,30 @@
+encoding=UTF-8
+#include /usr/share/wrapper/wrapper.conf
+
+wrapper.java.command=java
+wrapper.working.dir=/var/lib/freenet
+wrapper.java.classpath.1=/usr/share/java/freenet.jar
+wrapper.java.classpath.2=/usr/share/java/freenet-ext-29.jar
+wrapper.java.classpath.3=/usr/share/java/jna-4.5.2.jar
+wrapper.java.classpath.4=/usr/share/java/jna-platform-4.5.2.jar
+wrapper.java.classpath.5=/usr/share/java/bcprov-jdk15on-1.59.jar
+wrapper.java.classpath.6=/usr/share/java/pebble-3.1.5.jar
+wrapper.java.classpath.7=/usr/share/java/unbescape-1.1.6.RELEASE.jar
+wrapper.java.classpath.8=/usr/share/java/slf4j-api-1.7.25.jar
+
+wrapper.java.library.path.1=/usr/lib/jni
+wrapper.java.mainclass=freenet.node.NodeStarter
+wrapper.java.additional.1=-Dnetworkaddress.cache.ttl=0
+wrapper.java.additional.2=-Dnetworkaddress.cache.negative.ttl=0
+wrapper.java.additional.3=-Djava.net.preferIPv4Stack=false
+wrapper.java.additional.4=-Djava.io.tmpdir=./tmp/
+wrapper.java.additional.5=--illegal-access=permit
+wrapper.java.additional.6=--add-opens=java.base/java.lang=ALL-UNNAMED
+wrapper.java.additional.7=--add-opens=java.base/java.util=ALL-UNNAMED
+wrapper.java.additional.8=--add-opens=java.base/java.io=ALL-UNNAMED
+wrapper.java.additional.9=-Xss512k
+#wrapper.java.additional.3=-enableassertions:freenet
+# You might want to set the following line if you have changed java.maxmemory
+#wrapper.java.additional.4=-XX:MaxPermSize=
+wrapper.app.parameter.1=/etc/freenet/freenet.ini
+wrapper.logfile=/var/log/freenet/wrapper.log
diff --git a/devnotes/licenses/cryptics-general-license.txt b/devnotes/licenses/cryptics-general-license.txt
new file mode 100644
index 00000000000..ea382fdd3ae
--- /dev/null
+++ b/devnotes/licenses/cryptics-general-license.txt
@@ -0,0 +1,10 @@
+Cryptix General License
+
+Copyright © 1995-2001 The Cryptix Foundation Limited. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/gradle/verification-keyring.gpg b/gradle/verification-keyring.gpg
new file mode 100644
index 00000000000..d48a88918b7
Binary files /dev/null and b/gradle/verification-keyring.gpg differ
diff --git a/gradle/verification-keyring.keys b/gradle/verification-keyring.keys
new file mode 100644
index 00000000000..7cb57aff144
--- /dev/null
+++ b/gradle/verification-keyring.keys
@@ -0,0 +1,988 @@
+pub B341DDB020FCB6AB
+sub 315693699F8D102F
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQGiBEowbDsRBAD2jx/Q2jNuCkgiS3fzIj6EzDP+2kipIKH2LEnpnTiBlds2PFYM
+xYibVab/grgQODxTdDnAKifbJA/4h1/T7ba+OV+xIUoSI5MbgaF3USidiDHPX0pY
+qvG+k3hKECLysQ2zoZpcC8c2ePiZQSVC2i5BRqgs0xZPz3kiT5U9WPozTwCgtasB
+TgHhkOGhZ0SOUuQ4dL54R9cEAIaDjdPcI7LxyOMvvGTuW/SaS9JyP21Kch+Vf6I4
+vKWWqXEaF0So8S088zHnBrcBKhu9D1sKIHS64EoYCrznfMUtoENPe4sf5QuJmZ9D
++fBuFcudQIpkx8L73q+E3fmCK0uX+anqipJtS8mgpMeabKda4KkjDsZkiaNl7OBI
+0H09BACofK1HTNHNke2N0wXN1GyG7IAqprKl4lBbu5aRXvfKQ2tDj8s5webNQ+Se
+Om/Yg0Bi+CiONLgUjiwYe1wNls8zkk3LwYFeKIJ1AjAY3auBRWOI0/IFFzwTkV8J
+YPHa3Dl/kmYp8NMMwA5bgrblggM0Qhnp+k//xpb0FYbmwHMwUrkCDQRKMGw7EAgA
+5MMlt89bomqE0TSq63JnPaSeEKsAx6A1KaXaSg0LEI7fMebSQcAdVdAFBo4HaR+j
+NNGv5JGTvAObLrqxnn5mU/+qhdTw4WCf17R4ETEKc3iFN3xrpxz2Vew8ZWpw3PcE
+gCe27ZN02J6BgtEqhT9v9f0EkAgRHIkcaFCnxme1yPOFN+O0/n1A+59Ar8rmwcHG
+opSoZlGDEdEdqElx/shQjqq6Lx3bWYXS+fGzSAip+EAX/dh8S9mZuS6VCWjLx0St
+a1tuouq9PdOz5/4W/z4dF36XbZd1UZHkw7DSAUXYXfwfHPmrBOrLx8L+3nLjNnF4
+SSBd14AfOhnBcTQtvLuVMwADBQf8DC9ZhtJqHB/aXsQSrJtmoHbUHuOB3Hd8486U
+bZR+BPnnXQndt3Lm2zaSY3plWM2njxL42kuPVrhddLu4fWmWGhn/djFhUehZ7hsr
+Qw735eMPhWZQpFnXQBRX98ElZ4VVspszSBhybwlH39iCQBOv/IuR/tykWIxjPY7R
+H41EWcSOjJ1LJM2yrk/R+FidUyetedcwUApuDZHnH330Tl/1e+MYpmMzgdUGpU9v
+xZJHD9uzEbIxyTd2ky2y3R+n/6EkRt3AU9eI0IY1BqUh0wAuGv/Mq2aSDXXNYJ/p
+znXSQBjmy2tvJlqXn+wI1/ujRMHTTFUBySuMyZkC0PwUAAnWMYhJBBgRAgAJBQJK
+MGw7AhsMAAoJELNB3bAg/Larfc0AnAmQbEg9XnLr/t0iUS7+V7FcL5KpAJ9k3LS5
+JI97g3GZQ2CHkQwJ3+WcPw==
+=OasT
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 7C7D8456294423BA
+sub 9842FE565AA0601E
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQGiBEvsZw4RBADH20nX+H1xvMBYmXRj1Aae4dRr6Y6qI7QRWHO6Z7/dxr9bk/NN
+Yjq5KsVOQxZzloVdtqx75rznT7fZq98g7Nq9IeEtB6k4tnh6XQLhljJMk0a3mzdt
+q3VzdxeVbwCaPJ0zixv8XPTAH6MpRJUvP9XjzxwaYHrjwcQ1LslW4TrIzwCgi5rf
+jChLCyKcaL05gqUjl4lmefED/iqOwYZw5pJ8+X+OHUViiOB43wsJt1brAhPj4KgB
+ODStcE6WlHFKi7YzcYNLzYMebSGYn6bj65b3qNf6rybWD1hGUFK4122Q7+HCH9Ic
+J+rr8HwjGFo/yxI0/mkyaF0BthXYPy4WtdsdTM2kgx8Zr3Q2rSt1jBPuV3q8d27z
+FZMiA/9cWPkRx0RfAJmBPKmKkbBkEtBbNau3G7MY1OEAkEkRnzmnyyjr5IP84A7K
+RdjTCvkbiQrOQH00Ki4sHIg+9Xv1gDg1XLkFDzRARKA1TxjL0OeS4RWF3iia7Swk
+MOnTdhR50pjb18W8kB4mEMZY7duP4nwDfQwHMwbFZGHrjImaurkCDQRL7GcQEAgA
+thrbFDDbIGq97dbX1ZEwNGpjILdeumxZzaCc5PgldHGA86TL2V9iPpONJtv7/Csr
+1c/rvH0IA/BFu+0Kde9UP+z9JycmfJpIsd2Qtxfhn9R4+Td0VtN9NNkpt1+JcThb
+zyQq4UU82uBKwSG/wzubOI4Fn+7ypIuNgDkqK0STIL3ucKF/RV77PsOBeLHkCGKI
+VhUUfY1D51BWZKKB1efaVK7PLdnsi64lAhbaexA43dwUUtVwQOvDzJVtkycV2IMw
+XwyHonlK+4vbcwIH2BAU46LIZy+VFaI+lNNmR9+xeWH49oJYnMWIXif4RzvO1ag2
+KKwlG2sacuVTtpWVqKayBwADBQf7BGl4POKtluAbX3a/KGnX1YyibPT2e4pdOxqb
+KTwuRc7ILIK/LVcejVuLd+eOF1QmjToI7Y3qjlzvtaxSemfkxbIQpdus0SyHEEAG
+H/qjNuTs8ZwEl9tPPrKaJHbJ9kQrlDPwkufA0NDAXTE76UhcHPY0DeykAKEw2rav
+EqI7Y0nXR2WSmRLFChmQ+aNTm/9UGI/IoRdS/dgo1eaLD/7RLFeL5tGDe+2nj+B6
+j+52nZEmaRCWWU7O9jYL1cQu5WTurtneCLtIqehLsjuVz9ihBysYuUcTOV/6W0AI
+clQoMEiFR9Kyv0owDk6LtX2DgibJuAvvLlnajsiGm5nyVh3G1IhJBBgRAgAJBQJL
+7GcQAhsMAAoJEHx9hFYpRCO6iXUAnRcLw17lBhe/WcKFRkzETSxaJcjIAJ4/P1NN
+On/eScLdx27sje7q3sBENw==
+=TzHJ
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 3B17BFC1FCC1B644
+sub AB1D1A77026CB606
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBFro+cgBCADCxtYd7ZFChfyOnmp/rCtWS0DGY48wCmJTcgOyBFuTy8UJ+PdK
+e8aBsbpx6I5OM2WqvsGkqs/vboAbZxJ+G0br0qriXrz2SUQEJ7EMJJsUgkVSb/iO
+DEiqTr+XASuqVoCKsUnB+7eCWycsfODVYZbEjo52PZIJwiNS2yXBtYjf6t6i1rx0
+KrMF9dy9ZRWKe48UGK4KkZ5l9/yiM5CscJM3Wt5fBdFKpp8JmJQHMUivwURjT7dP
+o7ZDBLmvgs1/U55AJw9Uo7FwmNSoxr77OtGFaN6rmQS2w1jEt0ieujmuvj+z91sw
+FKQ8vxVBSLDtzDNP4NMA4Ie4G4sLDAzi0+1xABEBAAG5AQ0EWuj5yAEIALC3ywW3
+q+flFxeSpSuhLPNrJ1xzp5Ox8sZ/56f7PBEHYR4XAqyF5RLTaslHjxVkdq7JfQsi
+saoW48ToFGU4wt21A9Wgh+k6LpnO2CLPvZZmLmXYvikoU74JReCaLjxWLqgD5aQG
+6LakGNGgB4qHngFhccJozJn7irGUb2rJ58TkwAfbvghIKOvp2RI6dInKFEuIeWBz
+98v5xZp0HRbMnq0bd4RqNGXdJ3yJ2VyC4nVCw+IaZafVgI8MWSaQCiOgwVgS73kL
+wgX3xTFfsKMie8Kwo6zCYFyFekKdImG7w9yVavQmgSid2K+Xkb3qxpfjTZSM7qsK
+23nL/IoKChLu7eUAEQEAAYkBHwQYAQgACQUCWuj5yAIbDAAKCRA7F7/B/MG2RF3+
+B/46dH70jqBWl/8UtnV4/Tb3hNXb2vU3w7BTawg7qHmUPj0R6BBtRPQqvPxH7K62
+8ARhgBdEaVKMDA6ijSet7zJm2mU9DlBz+Yunz5a1jlDN/vXAzOQyA7jEd9iyI4Dn
+lWp+0Gy8EXEysV1mrXRQd0EwRp8kyozLpjAk+P3Xtu6OEHEWOJHZ67OzVLx/bOfU
+DIn5Sv8Dxi3cmaAj5ZjnCfM7a35nseGhFcezd+HjQy2v7W1X+zCJaDejdGe32pPU
+5Bx0+rqt7BzGjCtQ9N952neH8mAeLLhcpVQQqHx/YjIqJ1qfMPX6vXsur7fxJ1t0
+oY3gZlwqvKcRwJwExFAQotNX
+=Ql65
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub A6ADFC93EF34893E
+sub 9C4C23E6FFE405BD
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBE+xZxIBCACzKctn4ez8xOC0pGThhAwjYWGkzcwK4HNaC1usHThBFz3/t8JN
+OqUXRixLyi5wELN6GHlsGVUQS3IfB4JtuhScsieSB8PTree68/knMq6JI08mJqZr
+9nFrAB4eDW0UMbSL9kPmclUm/yN+qcCZBrsVn0q6CWb/Kcd8EEXEu6sGILzOGqGe
+d433t5O+tGXWL2TjAz+Scsk2Hf4zcuDeQcxELAMnVaVgKuGuEZvibrjsdIvJDGI+
+0BzWIu8ZP8ldBl4SVtzGpEVzLvDUo3mOqBeTkj3rP7xLtFDN/3AFtowbLfL7L2Pg
+SMcTnKK+jfFHRfbHP1Ih3rQ4ilLzhCnY/QIZABEBAAG5AQ0ET7FnEgEIAM3i3e1s
+jwrx2PN8XYMPQWG+/YTtw1BYDl2+iYE+LaZvtq1hpbgeCLgEVwXrCJ4spLP1rFXo
+gWqKrkJ0LRjlpdKhKBvyH1ex4grh3cWN/bIDJcJ7JA4I/Bhqhlh8hYycS9pGFeS+
+MR3aFIsii+vadrwYYvuVYGeWvdZhB7mJKYevj5Ms0OpYTfZd95Pzo4o//lNpDnrG
+7Xd3tgTNU/fkpw6rFB/2Ib1Qlk+Kz1z6JNsp+tOPGGCBrzwfwglcikTuqS+xyRgC
+9cHh5eCol11uSoWPKcQR2Ar8Eo56nxv/UApdu15iJ7R8cA5guKeeS4jt0CGCPs2P
+huggDxI73Xvl4zsAEQEAAYkBHwQYAQIACQUCT7FnEgIbDAAKCRCmrfyT7zSJPuyl
+B/9iwtIQeexMWBmQNdDe0md8HLulDfcujPtklrvYHtXMJQFaGA0Vafq0oT9MhBfb
+1YCP79uF0qgswSxINYCOJx4nTPIP9BOdTwqfGo7ul27REgNq4lIUW0GkMgZAUA2f
+t/vc0u/I0PqnhKCi4Pq79hLIx7eiX2ySfXfYfLXRVzbMWKMoi7lWXseQqbM0RvCA
+54J1qAi6Ew+JyoYGQ7OvXdL5Eh5Tkm2cpIADyqCkp/aFDe5lqZiU1zS2fU6mpOf/
+o0co+GoYkieIxxibDCmt3BioLgmyzpGUsMNwh4pAIQUGkcxd4spC0KIWdDEvq/QJ
+EEIhZlI/ojefaZkRseFrtl3X
+=pJaU
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 2189CA6247F3DEE5
+sub DC032628E927D006
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBFEsDjYBCADKUrv1zJObnlCQ/2AyexoofOuSSzj+L8AIRm2tm2qdPgYNYZHJ
+II661t4G5mg6QSGRlO1+NaD1S4GlcEpYvC860Uv26M9FbUAjlMJlWqLoNME9N1Oe
+eSLKs+C6RroY4qDuuA0UaLE1SQ9i5cm5bxPIfbm6aCcIzecTbfD18bxIq3fZrO2S
+yHek0H2upHAipKd2g2Ed4CikWZV2f8MoMZr7CLs4XgrmpEF01Ab5RBX01kX2MYaa
+Vk1BAc3FgLwA/azW3X1pdiyD4iAesHN6SlAaD7x2tZs8CrnRCaWLu31t+x+Sc4Uc
+zShjTGdB+euZykFpJW3t/D9BLicjRDTGjBfZABEBAAG5AQ0EUSwONgEIANijDStd
+yc4CSVYSXmX+ZQnWTF3gjYMkszD41yT129Xw1RTw//ayxYeBYruIgZb24eAULVhp
+hEEW9XgkXvPT1gvAlU27GJ5DYswuh+EIJGGjZMngvORS4Dvr+lkWXU347dgBIIHw
+vVl+rw2hUrnhn6Y/nBGWHRFWIXAMwQC2w61iwa2E1aLUJ1u3OvrC8U7Llmb76YOe
+qLGbOFiQN9vcr5orrqP/dAdTr4MoyS6dG7Lh8McfWwEDzq0Ygy5d0EJDudusApwc
+SQ9set/SO6b3F7IiQHAz2+sXlGJB1Kscx6tpbt5NRegKQp3qyZG71pp31QRePgbf
+O99L+AAv19DsQ40AEQEAAYkCRAQYAQIADwUCUSwONgIbLgUJB4YfgAEpCRAhicpi
+R/Pe5cBdIAQZAQIABgUCUSwONgAKCRDcAyYo6SfQBtuJB/sH31Gs3MKbEJksDtR3
+VKXGp+kll7BYSoVYv+llFcx7CxkAJNUQ/LH8l9Zbd/j8MA7e1V/ts/QkuLcLqtbe
+IdPWcHqXNSjFgOCIC46zGfV8dOmtjlblhfG8YvUZNnlEtJAFBtxOV+kKnMV7YWnS
+xm/slrbEFyaaQpicdtP+hw5ubWIAIzK+N3PbjXgKlIywSljU8iXsch2oCms8dAMY
+TQeqhnbq5VRjpIyGVrYzqubRLojeXWdCJ60rDvFHnqCyEJgKtxiWX4lQBGfdsnqK
+pmJNVv0X4CDHxyPUwChTtFLgNiJvJ2OoYJi5oEg0IZ0rt/9JNNwNnUYlB3qYCXU8
+3771PnwH/iql4tb/K9HUZMcZdjJ9cwljVbwL0Lk4SPeVuPkhTsRmSsrm9FHjOJkX
+RitmKnkQWbhBChV3oxVwklJTstYoGXHsUrHnmYV21C8y0HVGEuu2bGyWD7YaOH5c
+ayTK1jWK3Jm3BqFE1ORHQjPLMYd+ysGZsCFGcAGEL/3XBu0Tx1poq24uckus5XVk
+zq9Kt/d/C8lZR+TSi8In64cpKSl8ZuowN7h7gvldhC3A1jLu2vwyA2IBEaew3EbZ
+P0Trh3QbPrrKYy8ljK3LXa6TrtCpkO2JdQDC2Ih/3IS1ed2w6MML/Ss5trXwUuAN
+a2WwWwzksx7K6171af7wQ5jdvQaFDVM=
+=KJKl
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 3D52C2966A51F8F4
+sub 888C89049BDEB64C
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQGiBEqVGHgRBACyrZHA3gvzM5WeoD6WwQSIPdTPuWw5EUonHytf4m7pgX8Xkj2G
+enqbzW70POgJDUTUpvHDSCaAWiPY+ld1h0j+ghXgKD7IQjqFQTvnkdBT/qbOL7P1
+Umv5OLGSKeyx/BhxNiD0uF/huyP9b1HWC9dbIdVebhDcyBDkBAFtJMOxjwCgjnxw
+sUI5vJ5FMPDjUdRPTVQxwlkD/1PGN4Ycdn8ncmZ1OG0T+vmL+C+yGMIdbWIizffC
+Li05HMziwK33NHk5ABkeyIijm4Mq7JUlSSwt6gQXJTGlidHEcmKqSTg4AQhybPL5
+w40KcjNyAeQhIFgHAfMzy+Ikxzlt8fNunMTf6utWrPq2IU4uE4lJT4kSL1ic89vx
+a4CLA/4g4MJVuzTegJXS5vhMnEI2Nhmc2MIAsEhPcIwJjhUN4rJJMcVxQO+Cmrfl
+0rcosxA6wtjFDdPcuXYiAoJBJQrVYp6+w4GyHW45/WR6iGas/Rm0ZRQqnf9WnlpX
+o5d7uEwzLfck4iVw+z298y6qk52coFKaKPH0bGVxguifMNdbwbkCDQRKlRh4EAgA
+oSWTikKPMX99ZIqYgjAKlM82x6H5xxkisLGwI13m/nvRgOBy8gYzfJCdxrEupnvN
+k4PK7twUka18oAoaKfKFBdIKQ0bSyUNV/RzkJDhkBCCU0T8DbN7Xe4rP35l1PvSK
+OwtGmIxovip+Spm/j38KKnSTWyZ0JIBTOYEoB8wzyna/fcibwIy/M/wj+lrurXE/
+6QnAxqJjAsL2MtuTurC5IMfRPQqUL0yMk+l+wUpuBaWhg70NhbsTisdJy9TP+Nsu
+7tCJu3GumEuYKd3E46xIFedyA1etFHr9n7GkjQkrthlqaza2bUFOv2xOpTJOvZYr
+15zOCpHslcIQiWT5zWCQcwADBgf/WBNDvc3jNmAyTP3nLRbA2JP+tVBVwdQkHktY
+4EjaLC7HjUA5TblQFTycXtZyKJ+LUwXM2W47h4HMXhSRq7E/wzMUHGhUMBf21MwY
+//8mirKgRiU1rkArBKtr+bHTpsJ1UEoCaGzXxvTGxWZSLLrV1nBvbBXXOOhFKvCy
+mFcudN12i1MfBrubGNT905obseKThEc1umWzeRRWOlFEZkCONLR9PgSwCok7TT3O
+lkaGKRQB4cu54e/faOaLvFh2BgqSIoMgGHfVLJBTbssV6GL6T4YoU2Bq0wtLZ2k9
+tMgJHvPziWrk0rI4oesVWDmbEoRgAsYlTkdev0u98g3c5zAHLYhJBBgRAgAJBQJK
+lRh4AhsMAAoJED1SwpZqUfj05WEAnRNjXTAHWA3uXnDtK4XDHeCkqzUIAJwO+CnW
+RTDq7K7Q63sS3rHl9X9ZgA==
+=lGHK
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 2189CA6247F3DEE5
+sub DC032628E927D006
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBFEsDjYBCADKUrv1zJObnlCQ/2AyexoofOuSSzj+L8AIRm2tm2qdPgYNYZHJ
+II661t4G5mg6QSGRlO1+NaD1S4GlcEpYvC860Uv26M9FbUAjlMJlWqLoNME9N1Oe
+eSLKs+C6RroY4qDuuA0UaLE1SQ9i5cm5bxPIfbm6aCcIzecTbfD18bxIq3fZrO2S
+yHek0H2upHAipKd2g2Ed4CikWZV2f8MoMZr7CLs4XgrmpEF01Ab5RBX01kX2MYaa
+Vk1BAc3FgLwA/azW3X1pdiyD4iAesHN6SlAaD7x2tZs8CrnRCaWLu31t+x+Sc4Uc
+zShjTGdB+euZykFpJW3t/D9BLicjRDTGjBfZABEBAAG5AQ0EUSwONgEIANijDStd
+yc4CSVYSXmX+ZQnWTF3gjYMkszD41yT129Xw1RTw//ayxYeBYruIgZb24eAULVhp
+hEEW9XgkXvPT1gvAlU27GJ5DYswuh+EIJGGjZMngvORS4Dvr+lkWXU347dgBIIHw
+vVl+rw2hUrnhn6Y/nBGWHRFWIXAMwQC2w61iwa2E1aLUJ1u3OvrC8U7Llmb76YOe
+qLGbOFiQN9vcr5orrqP/dAdTr4MoyS6dG7Lh8McfWwEDzq0Ygy5d0EJDudusApwc
+SQ9set/SO6b3F7IiQHAz2+sXlGJB1Kscx6tpbt5NRegKQp3qyZG71pp31QRePgbf
+O99L+AAv19DsQ40AEQEAAYkCRAQYAQIADwUCUSwONgIbLgUJB4YfgAEpCRAhicpi
+R/Pe5cBdIAQZAQIABgUCUSwONgAKCRDcAyYo6SfQBtuJB/sH31Gs3MKbEJksDtR3
+VKXGp+kll7BYSoVYv+llFcx7CxkAJNUQ/LH8l9Zbd/j8MA7e1V/ts/QkuLcLqtbe
+IdPWcHqXNSjFgOCIC46zGfV8dOmtjlblhfG8YvUZNnlEtJAFBtxOV+kKnMV7YWnS
+xm/slrbEFyaaQpicdtP+hw5ubWIAIzK+N3PbjXgKlIywSljU8iXsch2oCms8dAMY
+TQeqhnbq5VRjpIyGVrYzqubRLojeXWdCJ60rDvFHnqCyEJgKtxiWX4lQBGfdsnqK
+pmJNVv0X4CDHxyPUwChTtFLgNiJvJ2OoYJi5oEg0IZ0rt/9JNNwNnUYlB3qYCXU8
+3771PnwH/iql4tb/K9HUZMcZdjJ9cwljVbwL0Lk4SPeVuPkhTsRmSsrm9FHjOJkX
+RitmKnkQWbhBChV3oxVwklJTstYoGXHsUrHnmYV21C8y0HVGEuu2bGyWD7YaOH5c
+ayTK1jWK3Jm3BqFE1ORHQjPLMYd+ysGZsCFGcAGEL/3XBu0Tx1poq24uckus5XVk
+zq9Kt/d/C8lZR+TSi8In64cpKSl8ZuowN7h7gvldhC3A1jLu2vwyA2IBEaew3EbZ
+P0Trh3QbPrrKYy8ljK3LXa6TrtCpkO2JdQDC2Ih/3IS1ed2w6MML/Ss5trXwUuAN
+a2WwWwzksx7K6171af7wQ5jdvQaFDVM=
+=KJKl
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 86E02C5A42196CA8
+uid Christian Grobmeier (Apache Codesigning)
+
+sub B4038E8B427473DA
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+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
+=B9qr
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 7C25280EAE63EBE5
+uid Oleg Kalnichevski
+uid Oleg Kalnichevski
+
+sub 926DFB2EDB329089
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+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
+ZNfGiQCfdH3+RPBbKSQofz2bGx7/niTd9qg=
+=CP3a
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub ECA081A9790D4FC4
+uid Ralph Schaer
+
+sub CEC8F362662576CF
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBEwwaQIBCAC/SIIRRSgKRDy1LGdgMiwnXSFCw6GmVHmcKw/EIZSgRwpr5c5G
+jIsdubpDLgICSCQcqiSYArx46nyBazksvvKji95oSBAdnuNMFD0XC5MdHBn5OE6I
+poa1CBnz/g2XTskrK85Ct+LelP6migrebK2pAKC5LuHn6nyFpb8C/ceQ3ou77yYj
+5i4/TP9QDFqnWL4tkdAhnoACmBil5sH8Kt0pR9fPtb+wDOnjtHDpb5FH5pPIN5zV
+EdP0k9MA6pp0wtWXavdMspJoxJctiqJ+AL8ejNqI7PbvXcUQ2A4k/oUYJUm2JU6g
+UGzs17pWDUE+xekjmTJEEKwhIVR8I8+dTzohABEBAAG0JFJhbHBoIFNjaGFlciA8
+cmFscGhzY2hhZXJAZ21haWwuY29tPokBOAQTAQIAIgUCTDBpAgIbAwYLCQgHAwIG
+FQgCCQoLBBYCAwECHgECF4AACgkQ7KCBqXkNT8RRHQgAlacmTmvQ2sti+9Sbwmzq
+lLwb0Lp9T4UXb9rmPt3dwpNOQmT1FAtjiGBjJ4/lm0wra4f7pQUOyhLr9ZmbD7QV
+m6z3/SjyBajDAGPQbmtASjhl6QU0EFetJhhIpiznuvCdX+DDltV3uMWHMdIp/XOJ
+IO6nu8guV07k85Ud0OmjXyBfqV54HbqQL5a9rEqYuBWDMGlQGjjbWbrMe0SZZUVt
+e2g9z6Ki4oisSvBS7ZQ3x4Uzz45fcfWWqIKstzyjfMJ5obITkkHXqEO/CQ+uR06f
+0NoB2CYGe59Ee4cRJ8R32pQJ1bfw4ehQsnOrcB3bj1taLspkPn/RG7+qYYVck1kU
+z7kBDQRMMGkCAQgAyLpmVFisy7DFYkTnvnDjAzkmjvtBKyjYytG/Le81L60wBbVe
+PhVAq1MaNikGtdm5ofjvQ9j7K/z8Mpn8KYExsNkNcrREZcuBswlOJZZvqsSDy8RY
+EUQ7rR7SgQEqSpBCqGVe96q08hoam0D2ohviokocoFr6JiGXYaXTnYsJKwZCgY3I
+r1FxVaXvkqqFwLGvPlGL28L6un5GTbplRJThOujaWtiOpjWt63GnJ35ukpOOKxtO
+H0MoYZwx8A/IN8J9nH7fR0c6y8pgloOcrDFRBacGSUJtxdy+qK/R225xF8eudO/G
+CXrVyxM1oMGL/MtnXfU1euZl0VENjLyDE+G+DwARAQABiQEfBBgBAgAJBQJMMGkC
+AhsMAAoJEOyggal5DU/EKtQIAKQW/u8UPr7fBs6ir/xSURK649reQdCREqEoZccX
+nwRUJAJwz75g2jNJeag/4VjgAVmoKELu8PnHBy5TeTeoDKhVfop8iwIZazdWG4ri
+lTWIdVdqq4viw7jktaVSyPo17wUJc1+YgKMprSk9fNptU9gD00P0RDcdrEmBzDe6
+mrZXlmNr9ecOU3hJRrAi6DDMdMsBCQTqownQqIKLX13akKk63TaSzO1/y/UcmLbj
+VbGAJ2YeyoirsXbAm5565Esrd+ZzFtUlYySFsma7MtE3Ry/U259VP9kcx6hET6Xq
+Q2QTcPh8Hht67/q6SyQGbHuvZZ17kvVHvYBP21xQPgPV5Kc=
+=ane8
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub BE096E29EDB8D141
+uid Eric Lafortune (Key for signing ProGuard artefacts)
+
+sub E05A9780475FAB55
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBFFGZXQBCADeZK9xuCrDwJ7v37y8RITlchzBfJEWv7cSbrSIBlFNAsUUoshW
+Y8U6xYKe0GdiLVta2F8bzs0Si4LcDeglQNi9Fxvh3/jfs0MEJUfSeZ4z1Mn5WY35
+utbdlHe6i+7qvhpHveREwWoWuvFGKeSCV8SioolG1mzxrDVLkQefPZ+Kr+xd2cYZ
+SIkbjdhCvJHcUkD9gs8Wz9q9eDyc7dGJmfBYaQ7Xa6lbd852qj8LjQ7Gd41yHU6T
+U3oo0kKfAPFkW7rX4zeJEBgpncK0i4ertd5to/y2hauqPU3VMExqNS0/L2GqKNmb
+Q2Me02pBSBCrLLCUJkm8jZorPNxlQxHpFLHDABEBAAG0T0VyaWMgTGFmb3J0dW5l
+IChLZXkgZm9yIHNpZ25pbmcgUHJvR3VhcmQgYXJ0ZWZhY3RzKSA8ZXJpY0BncmFw
+aGljcy5jb3JuZWxsLmVkdT6JATgEEwECACIFAlFGZXQCGwMGCwkIBwMCBhUIAgkK
+CwQWAgMBAh4BAheAAAoJEL4JbintuNFBUQ0H/1ahtWOeS+EEZqUxxgLE3aiuw6XR
+mcFY/9kRlnBsKpWGGyV0DRkLThXSV5fWwiP0+moef04Miv81txVXR3U5f4MY3U5J
+SDgeB1GK+BvcYz1CXxGcErgaMIDXu/K03OyQNp1lD2kjmDDz8SHdVqpv/aFfxWpL
+uMaogbStXfbDiMjeMg2zRcAzXqu7JlMt3z33uiTUZk9jubAPOBnP5/Yhuc2wcnfu
+cLUUL9xNE6gpl0Noy8qJ2TaVoHLfDEdSgVbLDNpippNQCIEXn8VtlBCG9FBtTUR7
+z8fGU8f+ijNYHMa6jNsDlSo45/RV+alQSSZhx3hPCIgO2klEkawBs0ikEjS5AQ0E
+UUZldAEIAL0CmXXJLZWMbKXEROAYFnUqQ4eNLUcLY1NfL9xrF2KP6apMXLJdftwz
+JtcenfD5vra8w5JJBn6cvY4Dr4zmueDSsN3Cpgr7c0trDNspAQMyUGmg4Cw7lAMr
+uIX2om1TTa5ALsQ1PfupnLFLFKbYd2MmfwEVHgEBAzqmr89RoG/NnlV4uxvWumb/
+OrLzzizGLHdLFjnq3Szl6wQPJwmxCtWHvzW/Y+HYclm+wp0sufvrXJ/G1RrHKxwh
+xaDVyLKsb5wkUC6SZmE477SP6ZCokoAGHqEK+5JnM9MYXreQ7N6NggRUseCokFaq
+ckze5wVBXmPuVAg76ScPFQd4JzLkGzUAEQEAAYkBHwQYAQIACQUCUUZldAIbDAAK
+CRC+CW4p7bjRQSkUCACPWdIvMXPtSQFnFR8oUIGxvcp9MYdealHNYkf3qgJTuWbH
+TeD8WpE53immju4hitOq/qDevKOWhcfSaLqCtdRyYQFFDWQt4SsiGdWfCvKiBMSM
+nrDQI9f+XCv7J3ute5alyMgv9Uo1XLyyiwhz9kJ9mzg+ENvy152PucI4TN63qMRQ
+MQbkAenrTzIer+5Q9ZY4TILC8pVVAIPQjTHuhdh8VMclTdkHab2PCFC57/3djJyY
+44PLhN3hLI4CElAGLUwBZLRa6OFOvwW5naivwgk0zeeTqq/jTOWPYiy2dyyX1pRX
+8bJh5et4mXyM7HLHRp+FblgWxpFWNvMCEpxujLsG
+=B/UT
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 15C71C0A4E0B8EDD
+sub 891E4C2D471515FE
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+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
+tiwy+wOBjaK9g3Kk8jsN3I8t
+=8Tiq
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 80C08B1C29100955
+uid Jake Wharton
+
+sub CF771F914C2A4A73
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQGiBE2fCWARBAC3v9wYo5kmynmVP+43ccamidflSLQjjpsXpSDLPFokGxeuw0OC
+QJy46m8b5ACoCqRlfwnRRcEHxiSlaBATJA6hi7NRO41R39C62JXsIxNJR16JNQ5k
+oG/NOAraw0E1RQIFslznQexfxPg4yFIVrsFp1wkpCRrCklatPMNap2DuNwCg7PWJ
+1vV93YIsaH0O2fnXz3E+6zsD/3cTzUWuySEDiCLNO3JYJm97v4NDQ93encP1Ooxh
+n+PSIP4GvjrAObh3FfWUucv8UGqcw5bAL7dA1z8SgKeyFk/afs2XofXdvC+PhZqC
+DwU0NiE0D/tDWqX0qIG4ezTU2uk+5dE/WVl3R10nOBgquQdWIdYKGfV4FNTiEduD
+Uw7fA/0XcwFom7eyR9eBonQmgIadljztm4gkv11lY33V1ZfJNndPKNzwevDwX+om
+/VEHvpEfPx5toD4H523BPx55ZtfowuMtFHZI718alpCo3h6xaDhGwXvsg3s9k03k
+rfxzCjf9qcJX1gb2JVZ2+2jCwUDQZeEwV2vivjGNiN9rShWW+7QkSmFrZSBXaGFy
+dG9uIDxqYWtld2hhcnRvbkBnbWFpbC5jb20+iGAEExECACAFAk2fCWACGwMGCwkI
+BwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCAwIscKRAJVQoeAKDLeCOKKnt5aqlHD/7+
+QPOgX4iYPACgvGRCubBztEBkU2xXbr9J2cQY5em5Ag0ETZ8JYBAIALeU4dgFKEn8
+b3E1LUT25svvUUX2kuVLQ5TzokC6zjWQrPehOlsYx+ey8RSN/6A5rBLtn1z75ror
+F3+vN5kLPAz8x2Th6Cxd6lvn3DQHfvDL0YHlp0AZzhHx5ogyJxdaqwzNy0JWxava
+FGN6b8bbrR1Nf08kq/d5dNe+NGVdBXcuqUo6jt1W+tkbntklS5e+B9/Q/4L8dYkl
+8xXRIMAuKw6h8j4LFXse6xndWeWtTIkfZImz0f7cLQV5X7QSv90i1KfzT9hLiUjp
+wqPydtTNuB6+gda64jFNhVcvgW+h7MH6FT/zSss2Jh2eDR4HFrv7EJSS8dKCvPox
+y8El8pQMG/8AAwUIAIXq+ryw44voH/IdbvTQtK4t5/lp/Oj9b7QrMR3u/iQxM4K3
+dq7rUbA8hjdMM3gfMu13B4pzGtpcf25b4NIIQkhES9+CUDQDYHF+gwkrwEascbdf
+YZiLAHtcMjW1Og+IhTY8wDuJT4I1pqumSzWV8UxVJctqNUTY2eU7158oD5+prdCc
+eQLbzxoKFtu056kZ2+46v6bAl8g/w8WoVORUuHruuvKohMVPHwNQws7KHCFy9YCr
+4yIQfqC8g8oITqlgUZcZaXx6K+NndwA6LAoXJL0edaZOZBuFq5H7Fkrw07+OIQFq
+LTGcFpR12AzDh9lmtyJQ8nVfb6IjAOSwBPlEZWSISQQYEQIACQUCTZ8JYAIbDAAK
+CRCAwIscKRAJVd58AJ0YA8xv0U5Odm8u21BvyxjGS3tBZACggF6P6KjhUPpIAYTS
+6v3TtzhkJdo=
+=Zirr
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 5F69AD087600B22C
+sub 0440006D577EAE4B
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBE7JURcBCADO+9Dc4/JnB+wX+fq+Fr2zUGSPOT6/qjE5kXL4FEbJKsqDSAKG
+VnbtRrsIUdmNIFQmz71bBDFhRBbrSrkz927k8eUPhYtxE2NmmWSuKgrjF4qviPQv
+m/7SqGx378m/qw4EvpgGUB8EYif98LYdWp5vsU/zx0Ps9auqvetAzJaL9489oE0F
+q8FVhve6BMfUUV7zOTCmJnf438YO68upjU0PVBdfFE6Qx4cgCeWbQGy2cooW5azN
+iIenhuYU1qikmxMHq2xZzN4uSTWLGDpimPyz+Y1aTSYJ/bgn9gPStbI9sojWo9SS
+5gvNK3XqJzMwxwFow86UcIE0vPD2T6ZlBAXRABEBAAG5AQ0ETslRFwEIANrjVe+1
+SPgEY9Xfe2+XGN/3q9DHHPP0PXLTGPuWKUmAzkBddNEAXTkPKtyCbH4WXhf4jBZR
+yFIpLkoGrW/yIeJZNfoq5xET7ldjDaAMNxb59/78JfyctGbEAgUlzueFONk3Dl0s
+DS5GDiWqJg4orqOtUcY+46oo6Z8ncKBbxIvOL+qv1KLWtzIoxjG81PUMk1/CfTij
+HgklKtLlbpOHs3m47/28AP2sf6kESKxBwzjgdSyeSci2nCuPoeSfLTJBJlsREL+z
+DaJES4G2nj6r/rXX9YHnuH9n0hNxFyhcY0ztsIyz1wqx0kiOYHnLIpUJ+2TcR/YN
+mFCYqZ/co98sDMUAEQEAAYkBHwQYAQIACQUCTslRFwIbDAAKCRBfaa0IdgCyLK1s
+B/97PLjfP4A523G01/uzf2X0AVyWfh/RhopJmESRNcaDnhLfTDqmchg02XxjP6jS
+ngxn2q+6XEUJTCvwODbbOROndTl/HwZFAbWGp8sozS5U98g4zulWldEgrIAMzY1G
+anOJcUvWrTepneZupViwHR4Ia17lei7IijkvveobXIaAr075u5nDyO8NeOsiUUsg
+gufj8mxt7pbeWOkAEpMCN2VgdLtDylKKoJcFp4KZbvtBYm9q8ULy99orOGK2Gmfl
+8KEervwYL9Gb2YsqZNe1JNe6w2/yX3i6g5+6Fuh5YIvSji20USIO78GVaNiMXKO2
+hsWaeXOM0n2j759uNb/Nd2XA
+=2J9s
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 2C7B12F2A511E325
+uid Ceki Gulcu
+
+sub 10DA72CD7FBFA159
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBE+ZO+EBCAC3fZOOuYKthr0GcUge0PH2bh18sbM9XUmPKQz/W15l1NA/2ARS
+2gUXM0R+SunMlun9KsqjnojJ2ObVPvbm1Hg/66JSRgR3JWfIpSlJxLicpfu8rCfN
+bOjh4v9ZipD+px8w3o/RNrnZH/KRsoJg9yER6pf+pUZqTJfdg5lXezc1WF+/1qVo
+ypldMGfrkfLsPrUZTT689ubbig978e7eYmJEqldtaIwaAzHQnB70wIJyg/rEwFUM
+ldsvs6t6czSuJ4zPMvmh8TMpTg9e6+DMktPl1CWRONl8RPpgYMIC96gb4OnfDDjk
+Ex6clSCwgbDwdeAyOjjR6pVq+pCNTo1Pcj5jABEBAAG0GENla2kgR3VsY3UgPGNl
+a2lAcW9zLmNoPokBOAQTAQIAIgUCT5k74QIbAwYLCQgHAwIGFQgCCQoLBBYCAwEC
+HgECF4AACgkQLHsS8qUR4yVwIwgAlj6R9Lxk/GnclmSvgtTyk1r5GxJ75iSCzs7q
+DlNuM6EfFbuZvLWORGgP8KtdQdh/bdICtRbh2eoW0vEKJKkl0ZI0/RnVMYKYpIHi
+KVUSjPq0svwDk5tUa7taNSdHfi9o1G1doBHyPu1u1xDVzMSWsbEvx6aVr2HkBDRy
+A+VcmnX6tokZjyRX4C9ldX3tR+ffn7v2Iy0bIesM92nMPnH/fPXWlnbQKTxQeMj2
+qYSl3H/NGp57G7KNSl1na5U8ueMcUtYb+eHphMsmaEb9xw8dM96CzIPZh1xMHNoQ
+NNJibURysbUpFlGUTOv6K0A392QkX3GwuCQGOeLWHOoQHD6Jt7kBDQRPmTvhAQgA
+trGiCYnW3tqvDzaStXsguVw67pou65dO7LTcrX+NTvejJZ9SrC89JsfiKBwtvyS3
+X/qiB+S7RP21PH7SYOy+orwDw1nacNNeiTdPnxQCDQVNeWpSpmbLlA+0b6K3aPf/
+EaCKndXmnQyXVOoSXZJ9bqAe0um0NRbO7M+L1KArVkWW56ms+DvHAeZaGnSDDHQp
+JI5haUqgSWWP/VoPEU1x0qiBZwY3lokSwRMISC4E/uiUvvm7rvfbBzfOiVrjNPLl
+sVPiQRgOTfQO7dUZAmt2yqWJt1Clliby4fgBVcOYUx0QCMiz8MZGtSB17+hSrC2C
+b1T6n0ypxuYyh4sV2LtqMQARAQABiQEfBBgBAgAJBQJPmTvhAhsMAAoJECx7EvKl
+EeMlX0UIAKS+4ZAKrGG9jbWfzTTDbu9zzkXgV13suMD+XcGz10DkdluTUBXj8wWl
+p289fXNm4E49ipsNK+dcZ+gOATjUvb1Llh6D6bHz1QM7olxBCeU2feTmYYKBH8GY
+Y9JZzfAXNMQhcNiiPj+ntZqePy/EFA4uZHM7We7vl2c7CBcDAq1NNeEczo0KvG7A
+Wt6QoaMVmbvA14EKadNzrmEy9apkag1BKvwzXInYCvIHMa9ZqicOSUcI5QCYu5Tu
+fvIE7Eq3Khh2Ex1FiOaEA+57LMrt6NsSKXrB8JNYbI5pqE1rxJXZnYtx3ZpPAAEf
+LjPdi1AOkWhvhsoPmiGFC6ebYQ5eVbI=
+=9O4j
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 7457CA33C3CE9E15
+sub ABE9F3126BB741C1
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBFIXyRQBCADe285y3Pu7KzoKyP6wqeNXtvvuwMatAmPm5x/i+S8MlryqzsYa
+x6twUmXV1yKjjtGrO+9fHvTOWBfSSP+fP9KTaTQYSasoJq2Mw4cQDy1i0zrxNZUw
+N4/BiyjQA25sdfaOolhO0sFlZuTZpYy5wG72KkA1ygNq0L+8aBKhEF6zDU61YzCC
+AxjcgTftgTeeoqkJtYa06lNz3jmJDN+zUQignfRa3ymoGtFHTzoXR9maE8RWDty4
+y+DY+8ibdGgSgKPZ0byTCDyNojgU1YTlADa/1/NY1ShYg617O1xicLNo0JEJlf2U
+Tu4Ymql36+xSkYSISU97Q6Utgq27XMuZvDUDABEBAAG5AQ0EUhfJFAEIAN9NHRd2
+bYP/3CDi+n1ilSChld0NR3DUBgS/AdqQ7IoAUfj7skyI/WyaMdV4uy6vRh5YgNg2
+g01nd0LLZR8Gf2Ck+D6F88CdZaTxlkcxHV/dXMZ8yBO+0D6yFRZEL7Imsv8Ig4QX
+OVwfuiXEPk/Ef5Dy9SdAVhcoErTGGR6BOGVVvexGtBwefsjMaOG0khkRbWIQ32Wx
+fUFuAv5XBQ0ckLrlKvYWUYhOlXg27GtFKH2EBBF0Z5ZWu7gaBFwSV0oLp9EWcD+C
++WEwUSfBdqfRJtyXvgf4kZdwdQ5caM8P2/Sdncl2l/LU1At2Smc+plr6zhIhDlLh
+lrzKGa16oARSBdUAEQEAAYkCPgQYAQoACQUCUhfJFAIbLgEpCRB0V8ozw86eFcBd
+IAQZAQoABgUCUhfJFAAKCRCr6fMSa7dBwURMCADHrqwRNHkbG1QsXJr9oUK6KVkL
+sPhcngIhxRLlqe89omg9G7eGNauzs2PKsB3txotCFc7ROVNv/TAuSDYzkPos8G46
+p3bGesjfJb24zc6GMT4RGIJoh1oNG1IciafIIHjp2ZJHRmEDwmvZG24OHJ+mlHLj
+aedtqlWu+zwwhH2VZrI/U3gW/x4imbk9UyyzciEIxrAc+fc19xl5PkUVcSDVC0cA
+qGpeZz8+SxFaf3Rr0aGnSbeuHRjNupmoxkQOAey1ztmdWiCPf5RFfmFD+fENh+/x
+qYiGorYpcIN7UAsMkvD5UHc5ZG2tTD41jM99w9Lm/xHJ9ks8gNwZESwIzr6ABKIH
+/1ulsflI216qPz5o7uUxlTm8NfTyATfCUuZEDMYGOjDQPqQa8hFebqjWWYBUq2Sl
+aKD2xMeEuEXV+M5k88Cx6T2nvaZWMsrD7uGj+tTsFaKBGxP5p2OSEWOTETKKv6Cx
+7vcMTQmrqSFo47bFKlNSs+aVM48UnQeFtTDyOhwa5jvtqtst4eQHwHWQ99BK0TEy
+mNx0vF0nPjWA76CRrfopOwXKdxJgoKq4MrxE92ot5I82AZBPeiWVJ+6wECeK/GoB
+IXZ5jEUqrQmmzIboWA5G5PMJ8egzLJNRJjTWHjCWrUTnwNcqaD4/qZxIlW4Lt0uv
+Glx6pKOJQ05u+9X/BzoVWrw=
+=ajY9
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 164BD2247B936711
+uid Marc Philipp (JUnit Development, 2014)
+
+sub EFE8086F9E93774E
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+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
+Qw==
+=iceo
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 1861C322C56014B2
+uid Niall Pemberton (Code signing)
+
+sub 9A347756830C4541
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+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
+co8an9pO9/oqU6vlZUr38w==
+=g8ME
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub A1B4460D8BA7B9AF
+uid Mockito (http://mockito.org)
+
+sub BA6D22590B3F9BEA
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBE4waOEBCADHDHNTq1NRR5TSooIrKY0BTQnaLfjKZfcJOwp+btBJrOUO7+e/
+V3M4DZQclj/e8SBiVmRPK8Oyrv6i5B5+Ee/qNlLjWiO10AJ/PLRjYdoW1V6PlTm7
+2aUxQ/wNXxDcOoH8M7Y4fEqZJ3rFuta8ogeIYnkUwUk3gc5YKk7KJDbiOXQfRxlY
+9MeVKyoYfj+2Szaaz98W097Pqf9+7i3WjB3TKR1pnWlzF6rLWIGBJqcJuTGLWUAB
+hwOMoNiIBAqyGu8E4rT8pP9OueprOeIjyKgOBWV5yctIxd7uu51sGR47TM2wmMmm
+r/Kz8FkMr1efof7Bx4mJuup6wQXonRMVBqpLABEBAAG0M01vY2tpdG8gKGh0dHA6
+Ly9tb2NraXRvLm9yZykgPG1vY2tpdG8ucGxAZ21haWwuY29tPokBOAQTAQIAIgUC
+TjBo4QIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQobRGDYunua/0Ewf/
+QRv2EXl6rlgV9LgXifdgD4ctYsMvhmJV0uaAaTvTcNpbYL0lG8FpCs0KHvBLWkoq
+esOdJYT4q/9msnBAMXS/9ckteDism8BwZR0qi9qzASzzMJEH7cdpr1te17JR0fl7
+8cgbGyw6UGfRSay9c3HyV0rCuQSFPMwQkG5YVpRiN6NSnYqDczS+aSjd6JCKu/4I
+LVgu4jH8oaUcGJEaWLmExSUzrUv9HFZXQJxLzrFT4k6AVVzBQCuEYW9XtgosKwfo
+0GweBXkC7iuO+bfNi84vyRLTkK50h4+rVNkyvNlgqknbeGrpvOvGErYJy24API/5
+TNP+ZLCTl7Y+qQejTFVJ4bkBDQROMGjhAQgAxDjlr6Oakgs+5d5NcIYpJ/8S5BIU
+aVlmjKoaFJoAy46WzvvpaTC022js1ZSvrM8wlSxSk+kD6/FAJw2pJwRgVrolOYJQ
+mqLqgTA2QSN+leWo0x8gC1+QXzrquCOd7m/+h8FHUDaxc29XQ+7+HtNvsSxY9dtD
+zgQGXjPXSppVCSiDNy1IuIAxmEAFSxok12Glxq/n2DFx6OnVB+5vvt0C8nQ6w0hQ
+AQKPUmO7fNav5lZMfKgR95NrvF1Hu5V6DZvpbXg6+NWfA8LsCampARrou5qzy67h
+b/+KKGHTDMOvZZlGw6oSnPngqmh06QqY7P4PKVkOo3Vb6+02ltyZ95RgmQARAQAB
+iQEfBBgBAgAJBQJOMGjhAhsMAAoJEKG0Rg2Lp7mv2b0IAI5pDzLtBGxYhmO1rSDg
+Y+JY7ZAr4srW/7K6Zc0RmWv48JsZOf7T78kIrif6jrF+ZwBLrdP93umMr9aJ/mJg
+lr+0oag0ZVhEW6Jb7dgiRn8F9+qcCs6lyozAG805oW2lULkwqSJ1xNs79v9RtOWl
+I5ruLVbS7XhGv0qH+ly1xpIuYOzNvpOgj1pC3Pv+NuL2hrLUZVg1vM9eCM3TDVbD
+yJZrxKdMemMSGHHsXWHtn8t4BT88kice4weDq8GBl1Dx+ApO1+iHj779nMX1Drfa
+xtJLTRqH9fhHesISmte8fPiydGT/HCA9quKUuxyN4W6Uwu+Uov12cGV2sAI+H5qP
+hF4=
+=FXjQ
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 33CD6733AF5EC452
+uid Dennis Lundberg (CODE SIGNING KEY)
+
+sub 3624EE1473A843C2
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+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
+v5JsdMMyJvQc+xtjXg7OVA==
+=RVv2
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 85911F425EC61B51
+uid Marc Philipp
+uid Open Source Development
+uid Marc Philipp
+uid Marc Philipp
+
+sub 8B2A34A7D4A9B8B3
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+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
+bpJ8mdzS2PJko7mm
+=7SBx
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 152888E10EF880B3
+uid Daniel Fernandez
+
+sub 1CB037909F7E059F
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+mQENBEtnRE8BCACzVmIkAALxSHQAbp5HCXCLqL16UnxJcrcUIcnRQSXiwjAcNsjS
+S1mRwr0WrmaquTQYDk1W8owUdmAXdTfSHgtJKFRKdJ20IymeXx1VrmUiiCNY9Jf1
+xYhaJAopMTeEp65q8enAZcxjyqVxk7wOPgKD6uakQDdwiJtWHsug7zlmUtzZ6Phk
+iCxhrJSasatOqQoJon+RMlsFYWLulDFv7CmDJq/GLS6bMDajKt+SXBsnKL/gUWZ4
+hT0sL4Ux6lkshyey1BSbmDbMnHmzR2Ng8oIzKziA900FFaAWsyg3S6vi6I4P/x4N
+PfOR2BiUwcPi7lA6Tp0lwPM0IdiUep9Nl13vABEBAAG0M0RhbmllbCBGZXJuYW5k
+ZXogPGRmZXJuYW5kZXpAdXNlcnMuc291cmNlZm9yZ2UubmV0PokBOAQTAQIAIgUC
+S2dETwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQFSiI4Q74gLNZ6Qf9
+G6Yr02yGjtoQEiKBhSRwyY44W+FBRLESFZ+M2yrVr74li0/1RVX0e0zyYUWQTWcY
+6ySzuvWdfqBlEeh+o7PPV5VwoBp/xHvbL8ufEREqjbL/0c/4O24ojTEWeOb7nGKr
+z5dxvy+fV6EzJfK37g3vYZoqy3uv1O8205UgzF84XpVW3pAmZRHz8G5+NapQD/nt
+p+zW1PqPK1FvRFxcMDsFhE0F4qAPB5W1jst+E/G3eyOeS5OxXePYiLaSlJo3XovP
+TgZKMZAu1WusPfrcTL+rzb8Rr/TQinb1jNkVCOyfqHk0Jfunda4dW8tgWLkau/A4
+eki1H5pOYEm7/lOQ3HRlLLkBDQRLZ0RPAQgArznjhUDrXc+Rj3JK5c9Kz7rIkRmj
+fvXAz/fWjgPGE75brZPcicuSY/DIMXglvYg4Nn2ELpfcdpA/2NbI9IbvBRvMm7lz
+un9mYlq4Id6kvpBhQbCg3ksyy6aailNB3oLN9Z3DFw2CnndDE9YuAkLHtSwR80yl
+M1Ain0OhHh+cPU9eoQSTZiPI4nmNFoLlIUmLHIqmGIndEsdkWg+BczFsc7ARKLn4
+1xHVg7/o1TBleyxUrLVp2LatNWZZdqD4pZfeAalrrmgTJHP89X++Qgtdt1baMWio
+mMUusUjxM+WuUSzPmYt8C2LG1dp8Dfvwr8DD98MrHwf1AkNfGGNSTWTWbQARAQAB
+iQEfBBgBAgAJBQJLZ0RPAhsMAAoJEBUoiOEO+ICzSdEIAIkL3iyzDsl8s76qY5EI
+JPodAYBeN85uA4V0tFdmnObUzas4Qkl8btGiYScQaeTBH+MepUqJiae59yOES2Yh
+y6bf9t1+WNkYUbPqvazSQgK1rujjlpvK33szMwaAr4OsiCXgLXjiiyUihNTu9yOn
+/kaV+ry1D1dVd05NgH/kHsGcXC7+bX9DrVYMzZd8vIDTK1cYEFSk/4f/ej5TkD1b
+VyuZpWG381vO/zchFeEFO68wd7KmVuUpfemZx4vaG6u/wA9DCulCVIhScBIXmLdw
+UWihEmfbGu3sZ3xuqmInxEJa8pPgjoTHTQ1KcUx8QDUSXg0Ne49z1DnRbB0ieTIV
+dqA=
+=llhr
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub BEDE11EAF1164480
+uid Joe Schmetzer
+
+sub 4BE257B370130000
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v1.68
+
+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
+33wjXAW0h+qq7/7Yq3w3/7ncv9sWIzU=
+=NtIH
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
new file mode 100644
index 00000000000..70d6d62ab8a
--- /dev/null
+++ b/gradle/verification-metadata.xml
@@ -0,0 +1,488 @@
+
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 28861d273a5..943f0cbfa75 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4230076d14a..171d8761b27 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip
-distributionSha256Sum=8626cbf206b4e201ade7b87779090690447054bc93f052954c78480fa6ed186e
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
+networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index cccdd3d517f..65dcd68d65c 100755
--- a/gradlew
+++ b/gradlew
@@ -1,78 +1,129 @@
-#!/usr/bin/env sh
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
+ JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -89,84 +140,105 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=$((i+1))
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
fi
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index e95643d6a2c..6689b85beec 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,4 +1,20 @@
-@if "%DEBUG%" == "" @echo off
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -9,19 +25,23 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +55,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,38 +65,26 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/src/freenet/client/ClientMetadata.java b/src/freenet/client/ClientMetadata.java
index 67c124fba02..2cc0a5bc82e 100644
--- a/src/freenet/client/ClientMetadata.java
+++ b/src/freenet/client/ClientMetadata.java
@@ -54,7 +54,7 @@ public static ClientMetadata construct(DataInputStream dis) throws MetadataParse
/** Get the document MIME type. Will always be a valid MIME type, unless there
* has been an error; if it is unknown, will return application/octet-stream. */
public String getMIMEType() {
- if((mimeType == null) || (mimeType.length() == 0))
+ if((mimeType == null) || mimeType.isEmpty())
return DefaultMIMETypes.DEFAULT_MIME_TYPE;
return mimeType;
}
@@ -64,13 +64,13 @@ public String getMIMEType() {
* existing information.
*/
public void mergeNoOverwrite(ClientMetadata clientMetadata) {
- if((mimeType == null) || mimeType.equals(""))
+ if((mimeType == null) || mimeType.isEmpty())
mimeType = clientMetadata.mimeType;
}
/** Is there no MIME type? */
public boolean isTrivial() {
- return ((mimeType == null) || mimeType.equals(""));
+ return ((mimeType == null) || mimeType.isEmpty());
}
@Override
diff --git a/src/freenet/client/DefaultMIMETypes.java b/src/freenet/client/DefaultMIMETypes.java
index b42c11fac6f..6f754eab351 100644
--- a/src/freenet/client/DefaultMIMETypes.java
+++ b/src/freenet/client/DefaultMIMETypes.java
@@ -65,25 +65,24 @@ protected static synchronized void addMIMEType(short number, String type) {
*/
protected static synchronized void addMIMEType(short number, String type, String[] extensions, String outExtension) {
addMIMEType(number, type);
- Short t = Short.valueOf(number);
if(extensions != null) {
for(String ext : extensions) {
ext = ext.toLowerCase();
Short s = mimeTypesByExtension.get(ext);
if(s != null) {
// No big deal
- Logger.normal(DefaultMIMETypes.class, "Extension "+ext+" assigned to "+byNumber(s.shortValue())+" in preference to "+number+ ':' +type);
+ Logger.normal(DefaultMIMETypes.class, "Extension "+ext+" assigned to "+byNumber(s)+" in preference to "+number+ ':' +type);
} else {
// If only one, make it primary
if((outExtension == null) && (extensions.length == 1))
- primaryExtensionByMimeNumber.put(t, ext);
- mimeTypesByExtension.put(ext, t);
+ primaryExtensionByMimeNumber.put(number, ext);
+ mimeTypesByExtension.put(ext, number);
}
}
- allExtensionsByMimeNumber.put(t, extensions);
+ allExtensionsByMimeNumber.put(number, extensions);
}
if(outExtension != null)
- primaryExtensionByMimeNumber.put(t, outExtension);
+ primaryExtensionByMimeNumber.put(number, outExtension);
}
@@ -118,9 +117,7 @@ public synchronized static String byNumber(short x) {
* types, in which case it will have to be sent uncompressed.
*/
public synchronized static short byName(String s) {
- Short x = mimeTypesByName.get(s);
- if(x != null) return x.shortValue();
- else return -1;
+ return mimeTypesByName.getOrDefault(s, (short) -1);
}
/* From toad's /etc/mime.types
@@ -754,6 +751,10 @@ public synchronized static short byName(String s) {
addMIMEType((short)619, "audio/speex", "spx");
addMIMEType((short)620, "audio/ogg", "oga");
addMIMEType((short)621, "audio/flac", "flac");
+ addMIMEType((short)622, "image/webp", "webp");
+ addMIMEType((short)623, "image/avif", "avif");
+ addMIMEType((short)624, "image/heic", "heic");
+ addMIMEType((short)625, "image/heif", "heif");
}
/** Guess a MIME type from a filename.
diff --git a/src/freenet/client/FailureCodeTracker.java b/src/freenet/client/FailureCodeTracker.java
index 88731eeea68..4339aea8217 100644
--- a/src/freenet/client/FailureCodeTracker.java
+++ b/src/freenet/client/FailureCodeTracker.java
@@ -50,7 +50,7 @@ public FailureCodeTracker(boolean isInsert, SimpleFieldSet fs) {
int num = Integer.parseInt(name);
int count = Integer.parseInt(f.get("Count"));
if(count < 0) throw new IllegalArgumentException("Count < 0");
- map.put(Integer.valueOf(num), count);
+ map.put(num, count);
total += count;
}
}
@@ -135,7 +135,7 @@ public synchronized String toString() {
if(map == null) return super.toString()+":empty";
StringBuilder sb = new StringBuilder(super.toString());
sb.append(':');
- if(map.size() == 0) sb.append("empty");
+ if(map.isEmpty()) sb.append("empty");
else if(map.size() == 1) {
sb.append("one:");
Integer code = (Integer) (map.keySet().toArray())[0];
@@ -192,7 +192,7 @@ public synchronized SimpleFieldSet toFieldSet(boolean verbose) {
for (Map.Entry e : map.entrySet()) {
Integer k = e.getKey();
Integer item = e.getValue();
- int code = k.intValue();
+ int code = k;
// prefix.num.Description=
// prefix.num.Count=
if(verbose)
@@ -219,7 +219,7 @@ public InsertExceptionMode getFirstCodeInsert() {
}
public synchronized int getFirstCode() {
- return ((Integer) map.keySet().toArray()[0]).intValue();
+ return (Integer) map.keySet().toArray()[0];
}
public synchronized boolean isFatal(boolean insert) {
diff --git a/src/freenet/client/FetchContext.java b/src/freenet/client/FetchContext.java
index cec1f19bb4d..381624140ee 100644
--- a/src/freenet/client/FetchContext.java
+++ b/src/freenet/client/FetchContext.java
@@ -406,13 +406,13 @@ public FetchContext(DataInputStream dis) throws StorageFormatException, IOExcept
}
}
String s = dis.readUTF();
- if(s.equals(""))
+ if(s.isEmpty())
charset = null;
else
charset = s;
canWriteClientCache = dis.readBoolean();
s = dis.readUTF();
- if(s.equals(""))
+ if(s.isEmpty())
overrideMIME = null;
else
overrideMIME = s;
@@ -425,7 +425,7 @@ public FetchContext(DataInputStream dis) throws StorageFormatException, IOExcept
// input stream reached EOF, so it must have been and old version without scehmeHostAndPort.
s = "";
}
- if (s.equals("")) {
+ if (s.isEmpty()) {
schemeHostAndPort = null;
} else {
schemeHostAndPort = s;
diff --git a/src/freenet/client/FetchException.java b/src/freenet/client/FetchException.java
index 5e761085ee7..4fb2d3e0967 100644
--- a/src/freenet/client/FetchException.java
+++ b/src/freenet/client/FetchException.java
@@ -353,7 +353,7 @@ public static String getShortMessage(FetchExceptionMode mode) {
// FIXME change the l10n to use the names rather than codes
int code = mode.code;
String ret = NodeL10n.getBase().getString("FetchException.shortError."+code);
- if(ret == null || ret.equals(""))
+ if(ret == null || ret.isEmpty())
return "Unknown code "+mode;
else return ret;
}
diff --git a/src/freenet/client/HighLevelSimpleClientImpl.java b/src/freenet/client/HighLevelSimpleClientImpl.java
index d4bc0fe392a..cf177bdbde8 100644
--- a/src/freenet/client/HighLevelSimpleClientImpl.java
+++ b/src/freenet/client/HighLevelSimpleClientImpl.java
@@ -97,14 +97,14 @@ public HighLevelSimpleClientImpl(NodeClientCore node, BucketFactory bf, RandomSo
this.core = node;
this.priorityClass = priorityClass;
bucketFactory = bf;
- this.persistentFileTracker = node.persistentTempBucketFactory;
+ this.persistentFileTracker = node.getPersistentTempBucketFactory();
random = r;
this.eventProducer = new SimpleEventProducer();
eventProducer.addEventListener(new EventLogger(LogLevel.MINOR, false));
curMaxLength = Long.MAX_VALUE;
curMaxTempLength = Long.MAX_VALUE;
curMaxMetadataLength = 1024 * 1024;
- this.persistentBucketFactory = node.persistentTempBucketFactory;
+ this.persistentBucketFactory = node.getPersistentTempBucketFactory();
this.realTimeFlag = realTimeFlag;
}
@@ -148,7 +148,7 @@ public FetchResult fetch(FreenetURI uri) throws FetchException {
FetchWaiter fw = new FetchWaiter(this);
ClientGetter get = new ClientGetter(fw, uri, context, priorityClass, null, null, null);
try {
- core.clientContext.start(get);
+ core.getClientContext().start(get);
} catch (PersistenceDisabledException e) {
// Impossible
}
@@ -165,7 +165,7 @@ public FetchResult fetchFromMetadata(Bucket initialMetadata) throws FetchExcepti
FetchWaiter fw = new FetchWaiter(this);
ClientGetter get = new ClientGetter(fw, FreenetURI.EMPTY_CHK_URI, context, priorityClass, null, null, initialMetadata);
try {
- core.clientContext.start(get);
+ core.getClientContext().start(get);
} catch (PersistenceDisabledException e) {
// Impossible
}
@@ -184,7 +184,7 @@ public FetchResult fetch(FreenetURI uri, long overrideMaxSize, RequestClient cli
FetchContext context = getFetchContext(overrideMaxSize);
ClientGetter get = new ClientGetter(fw, uri, context, priorityClass, null, null, null);
try {
- core.clientContext.start(get);
+ core.getClientContext().start(get);
} catch (PersistenceDisabledException e) {
// Impossible
}
@@ -211,7 +211,7 @@ public ClientGetter fetch(FreenetURI uri, ClientGetCallback callback, FetchConte
if(uri == null) throw new NullPointerException();
ClientGetter get = new ClientGetter(callback, uri, fctx, prio, null, null, null);
try {
- core.clientContext.start(get);
+ core.getClientContext().start(get);
} catch (PersistenceDisabledException e) {
// Impossible
}
@@ -223,7 +223,7 @@ public ClientGetter fetchFromMetadata(Bucket initialMetadata, ClientGetCallback
if(initialMetadata == null) throw new NullPointerException();
ClientGetter get = new ClientGetter(callback, FreenetURI.EMPTY_CHK_URI, fctx, prio, null, null, initialMetadata);
try {
- core.clientContext.start(get);
+ core.getClientContext().start(get);
} catch (PersistenceDisabledException e) {
// Impossible
}
@@ -259,9 +259,9 @@ public FreenetURI insert(InsertBlock insert, String filenameHint, boolean isMeta
PutWaiter pw = new PutWaiter(this);
ClientPutter put = new ClientPutter(pw, insert.getData(), insert.desiredURI, insert.clientMetadata,
ctx, priority,
- isMetadata, filenameHint, false, core.clientContext, forceCryptoKey, -1);
+ isMetadata, filenameHint, false, core.getClientContext(), forceCryptoKey, -1);
try {
- core.clientContext.start(put);
+ core.getClientContext().start(put);
} catch (PersistenceDisabledException e) {
// Impossible
}
@@ -277,9 +277,9 @@ public ClientPutter insert(InsertBlock insert, String filenameHint, boolean isMe
public ClientPutter insert(InsertBlock insert, String filenameHint, boolean isMetadata, InsertContext ctx, ClientPutCallback cb, short priority) throws InsertException {
ClientPutter put = new ClientPutter(cb, insert.getData(), insert.desiredURI, insert.clientMetadata,
ctx, priority,
- isMetadata, filenameHint, false, core.clientContext, null, -1);
+ isMetadata, filenameHint, false, core.getClientContext(), null, -1);
try {
- core.clientContext.start(put);
+ core.getClientContext().start(put);
} catch (PersistenceDisabledException e) {
// Impossible
}
@@ -321,12 +321,12 @@ public FreenetURI insertManifest(FreenetURI insertURI, HashMap b
PutWaiter pw = new PutWaiter(this);
DefaultManifestPutter putter;
try {
- putter = new DefaultManifestPutter(pw, BaseManifestPutter.bucketsByNameToManifestEntries(bucketsByName), priorityClass, insertURI, defaultName, getInsertContext(true), false, forceCryptoKey, core.clientContext);
+ putter = new DefaultManifestPutter(pw, BaseManifestPutter.bucketsByNameToManifestEntries(bucketsByName), priorityClass, insertURI, defaultName, getInsertContext(true), false, forceCryptoKey, core.getClientContext());
} catch (TooManyFilesInsertException e1) {
throw new InsertException(InsertExceptionMode.TOO_MANY_FILES);
}
try {
- core.clientContext.start(putter);
+ core.getClientContext().start(putter);
} catch (PersistenceDisabledException e) {
// Impossible
}
@@ -419,12 +419,12 @@ public void prefetch(FreenetURI uri, long timeout, long maxSize, Set all
core.getTicker().queueTimedJob(new Runnable() {
@Override
public void run() {
- get.cancel(core.clientContext);
+ get.cancel(core.getClientContext());
}
}, timeout);
try {
- core.clientContext.start(get);
+ core.getClientContext().start(get);
} catch (FetchException e) {
// Ignore
} catch (PersistenceDisabledException e) {
diff --git a/src/freenet/client/Metadata.java b/src/freenet/client/Metadata.java
index 6075b53bf0f..672d2e2ee0d 100644
--- a/src/freenet/client/Metadata.java
+++ b/src/freenet/client/Metadata.java
@@ -10,8 +10,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
-import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
+import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.LinkedList;
@@ -440,7 +440,7 @@ public Metadata(DataInputStream dis, long length) throws IOException, MetadataPa
byte[] toRead = new byte[len];
dis.readFully(toRead);
// Use UTF-8 for everything, for simplicity
- mimeType = new String(toRead, "UTF-8");
+ mimeType = new String(toRead, StandardCharsets.UTF_8);
if(logMINOR) Logger.minor(this, "Raw MIME");
if(!DefaultMIMETypes.isPlausibleMIMEType(mimeType))
throw new MetadataParseException("Does not look like a MIME type: \""+mimeType+"\"");
@@ -687,7 +687,7 @@ else if(splitfileSingleCryptoAlgorithm == Key.ALGO_AES_CTR_256_SHA256) {
short nameLength = dis.readShort();
byte[] buf = new byte[nameLength];
dis.readFully(buf);
- String name = new String(buf, "UTF-8").intern();
+ String name = new String(buf, StandardCharsets.UTF_8).intern();
if(logMINOR) Logger.minor(this, "Entry "+i+" name "+name);
short len = dis.readShort();
if(len < 0)
@@ -707,9 +707,9 @@ else if(splitfileSingleCryptoAlgorithm == Key.ALGO_AES_CTR_256_SHA256) {
if(logMINOR) Logger.minor(this, "Reading archive internal redirect length "+len);
byte[] buf = new byte[len];
dis.readFully(buf);
- targetName = new String(buf, "UTF-8");
+ targetName = new String(buf, StandardCharsets.UTF_8);
while(true) {
- if(targetName.isEmpty()) throw new MetadataParseException("Invalid target name is empty: \""+new String(buf, "UTF-8")+"\"");
+ if(targetName.isEmpty()) throw new MetadataParseException("Invalid target name is empty: \""+new String(buf, StandardCharsets.UTF_8)+"\"");
if(targetName.charAt(0) == '/') {
targetName = targetName.substring(1);
continue;
@@ -719,23 +719,9 @@ else if(splitfileSingleCryptoAlgorithm == Key.ALGO_AES_CTR_256_SHA256) {
}
}
- private static final byte[] SPLITKEY;
- static {
- try {
- SPLITKEY = "SPLITKEY".getBytes("UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new Error(e);
- }
- }
+ private static final byte[] SPLITKEY = "SPLITKEY".getBytes(StandardCharsets.UTF_8);
- private static final byte[] CROSS_SEGMENT_SEED;
- static {
- try {
- CROSS_SEGMENT_SEED = "CROSS_SEGMENT_SEED".getBytes("UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new Error(e);
- }
- }
+ private static final byte[] CROSS_SEGMENT_SEED = "CROSS_SEGMENT_SEED".getBytes(StandardCharsets.UTF_8);
public static byte[] getCryptoKey(HashResult[] hashes) {
if(hashes == null || hashes.length == 0 || !HashResult.contains(hashes, HashType.SHA256))
@@ -750,9 +736,7 @@ public static byte[] getCryptoKey(byte[] hash) {
MessageDigest md = SHA256.getMessageDigest();
md.update(hash);
md.update(SPLITKEY);
- byte[] buf = md.digest();
- SHA256.returnMessageDigest(md);
- return buf;
+ return md.digest();
}
public static byte[] getCrossSegmentSeed(HashResult[] hashes, byte[] hashThisLayerOnly) {
@@ -771,9 +755,7 @@ public static byte[] getCrossSegmentSeed(byte[] hash) {
MessageDigest md = SHA256.getMessageDigest();
md.update(hash);
md.update(CROSS_SEGMENT_SEED);
- byte[] buf = md.digest();
- SHA256.returnMessageDigest(md);
- return buf;
+ return md.digest();
}
/**
@@ -867,7 +849,7 @@ private void addRedirectionManifestWithMetadata(HashMap dir) {
Logger.debug(this, "Putting metadata for "+key);
manifestEntries.put(key, data);
} else if(o instanceof HashMap) {
- if(key.equals("")) {
+ if(key.isEmpty()) {
Logger.error(this, "Creating a subdirectory called \"\" - it will not be possible to access this through fproxy!", new Exception("error"));
}
HashMap hm = Metadata.forceMap(o);
@@ -1327,7 +1309,7 @@ public HashMap getDocuments() {
HashMap docs = new HashMap();
for (Map.Entry entry: manifestEntries.entrySet()) {
String st = entry.getKey();
- if (st.length()>0)
+ if (!st.isEmpty())
docs.put(st, entry.getValue());
}
return docs;
@@ -1523,7 +1505,7 @@ public void writeTo(DataOutputStream dos) throws IOException, MetadataUnresolved
if(hasCompressedMIMEParams)
dos.writeShort(compressedMIMEParams);
} else {
- byte[] data = mimeType.getBytes("UTF-8");
+ byte[] data = mimeType.getBytes(StandardCharsets.UTF_8);
if(data.length > 255) throw new Error("MIME type too long: "+data.length+" bytes: "+mimeType);
dos.writeByte((byte)data.length);
dos.write(data);
@@ -1576,7 +1558,7 @@ public void writeTo(DataOutputStream dos) throws IOException, MetadataUnresolved
LinkedList unresolvedMetadata = null;
for(Map.Entry entry: manifestEntries.entrySet()) {
String name = entry.getKey();
- byte[] nameData = name.getBytes("UTF-8");
+ byte[] nameData = name.getBytes(StandardCharsets.UTF_8);
if(nameData.length > Short.MAX_VALUE) throw new IllegalArgumentException("Manifest name too long");
dos.writeShort(nameData.length);
dos.write(nameData);
@@ -1618,7 +1600,7 @@ public void writeTo(DataOutputStream dos) throws IOException, MetadataUnresolved
}
if((documentType == DocumentType.ARCHIVE_INTERNAL_REDIRECT) || (documentType == DocumentType.ARCHIVE_METADATA_REDIRECT) || (documentType == DocumentType.SYMBOLIC_SHORTLINK)) {
- byte[] data = targetName.getBytes("UTF-8");
+ byte[] data = targetName.getBytes(StandardCharsets.UTF_8);
if(data.length > Short.MAX_VALUE) throw new IllegalArgumentException("Archive internal redirect name too long");
dos.writeShort(data.length);
dos.write(data);
diff --git a/src/freenet/client/async/BaseManifestPutter.java b/src/freenet/client/async/BaseManifestPutter.java
index 062d5c7eb5d..81d4d122e49 100644
--- a/src/freenet/client/async/BaseManifestPutter.java
+++ b/src/freenet/client/async/BaseManifestPutter.java
@@ -71,7 +71,7 @@ public abstract class BaseManifestPutter extends ManifestPutter {
* ArchivePutHandler - wrapper for ContainerInserter
*
* Archives are not part of the site structure, they are used to group files that
- * not fit into a container (for example a directory with brazilion files it)
+ * not fit into a container (for example a directory with a bazillion files in it)
* Archives are always inserted as CHK, references to items in it
* are normal redirects to CHK@blah,blub,AA/nameinarchive
*
@@ -326,7 +326,7 @@ public void onSuccess(ClientPutState state, ClientContext context) {
}
}
- /** Placeholder for Matadata, don't run it! */
+ /** Placeholder for Metadata, don't run it! */
private final class JokerPutHandler extends PutHandler {
private static final long serialVersionUID = 1L;
@@ -1584,7 +1584,7 @@ public static ManifestElement[] flatten(HashMap manifestElements)
public static void flatten(HashMap manifestElements, List v, String prefix) {
for(Map.Entry entry: manifestElements.entrySet()) {
String name = entry.getKey();
- String fullName = prefix.length() == 0 ? name : prefix+ '/' +name;
+ String fullName = prefix.isEmpty() ? name : prefix+ '/' +name;
Object o = entry.getValue();
if(o instanceof HashMap) {
flatten(Metadata.forceMap(o), v, fullName);
diff --git a/src/freenet/client/async/ClientGetter.java b/src/freenet/client/async/ClientGetter.java
index b63a3b09897..c2ef942e6b7 100644
--- a/src/freenet/client/async/ClientGetter.java
+++ b/src/freenet/client/async/ClientGetter.java
@@ -522,7 +522,7 @@ public void onFailure(FetchException e, ClientGetState state, ClientContext cont
String mime = e.getExpectedMimeType();
if(ctx.overrideMIME != null)
mime = ctx.overrideMIME;
- if(mime != null && !"".equals(mime)) {
+ if(mime != null && !mime.isEmpty()) {
// Even if it's the default, it is set because we have the final size.
UnsafeContentTypeException unsafe = ContentFilter.checkMIMEType(mime);
if(unsafe != null) {
@@ -777,7 +777,7 @@ public void onExpectedMIME(ClientMetadata clientMetadata, ClientContext context)
mime = clientMetadata.getMIMEType();
if(ctx.overrideMIME != null)
mime = ctx.overrideMIME;
- if(mime == null || mime.equals("")) return;
+ if(mime == null || mime.isEmpty()) return;
synchronized(this) {
expectedMIME = mime;
}
diff --git a/src/freenet/client/async/ClientPutter.java b/src/freenet/client/async/ClientPutter.java
index 686a5371805..68fcb2be038 100644
--- a/src/freenet/client/async/ClientPutter.java
+++ b/src/freenet/client/async/ClientPutter.java
@@ -54,7 +54,7 @@ public class ClientPutter extends BaseClientPutter implements PutCompletionCallb
/** The final URI for the data. */
private FreenetURI uri;
private final byte[] overrideSplitfileCrypto;
- /** Random or overriden splitfile cryptokey. Valid after start(). */
+ /** Random or overridden splitfile cryptokey. Valid after start(). */
private byte[] cryptoKey;
/** When positive, means we will return metadata rather than a URI, once the
* metadata is under this length. If it is too short it is still possible to
@@ -84,7 +84,7 @@ public void shouldUpdate(){
* @param isMetadata
* @param targetFilename If set, create a one-file manifest containing this filename pointing to this file.
* @param binaryBlob
- * @param context The client object for purposs of round-robin client balancing.
+ * @param context The client object for purposes of round-robin client balancing.
* @param overrideSplitfileCrypto
* @param metadataThreshold
*/
diff --git a/src/freenet/client/async/ClientRequestScheduler.java b/src/freenet/client/async/ClientRequestScheduler.java
index 3f92303cb6f..f1575ca51c3 100644
--- a/src/freenet/client/async/ClientRequestScheduler.java
+++ b/src/freenet/client/async/ClientRequestScheduler.java
@@ -69,7 +69,7 @@ public ClientRequestScheduler(boolean forInserts, boolean forSSKs, boolean forRT
this.isSSKScheduler = forSSKs;
this.isRTScheduler = forRT;
schedTransient = new KeyListenerTracker(forInserts, forSSKs, forRT, random, this, null, false);
- this.datastoreChecker = core.storeChecker;
+ this.datastoreChecker = core.getStoreChecker();
this.starter = starter;
this.random = random;
this.node = node;
diff --git a/src/freenet/client/async/ClientRequestSelector.java b/src/freenet/client/async/ClientRequestSelector.java
index e9ba47f98d6..857415a2980 100644
--- a/src/freenet/client/async/ClientRequestSelector.java
+++ b/src/freenet/client/async/ClientRequestSelector.java
@@ -596,7 +596,7 @@ public void removeRunningInsert(SendableRequestItemKey token) {
@Override
public long checkRecentlyFailed(Key key, boolean realTime) {
Node node = sched.getNode();
- return node.clientCore.checkRecentlyFailed(key, realTime);
+ return node.getClientCore().checkRecentlyFailed(key, realTime);
}
/** Add a request (or insert) to the request selection tree.
diff --git a/src/freenet/client/async/ClientRequester.java b/src/freenet/client/async/ClientRequester.java
index 901eeece2c3..65f0240cdb5 100644
--- a/src/freenet/client/async/ClientRequester.java
+++ b/src/freenet/client/async/ClientRequester.java
@@ -16,7 +16,6 @@
import freenet.node.SendableRequest;
import freenet.node.useralerts.SimpleUserAlert;
import freenet.node.useralerts.UserAlert;
-import freenet.support.CurrentTimeUTC;
import freenet.support.Logger;
import freenet.support.Logger.LogLevel;
import freenet.support.io.ResumeFailedException;
@@ -125,10 +124,12 @@ public int hashCode() {
protected int totalBlocks;
/** Number of blocks we have successfully completed a fetch/put for. */
protected int successfulBlocks;
- /**
- * ATTENTION: This may be null for very old databases.
- * @see #getLatestSuccess() Explanation of the content and especially the default value. */
- protected Date latestSuccess = CurrentTimeUTC.get();
+ /**
+ * ATTENTION: This may be null for very old databases.
+ *
+ * @see #getLatestSuccess() Explanation of the content and especially the default value.
+ */
+ protected Date latestSuccess = new Date();
/** Number of blocks which have failed. */
protected int failedBlocks;
/** Number of blocks which have failed fatally. */
@@ -174,8 +175,8 @@ public Date getLatestFailure() {
protected synchronized void resetBlocks() {
totalBlocks = 0;
successfulBlocks = 0;
- // See ClientRequester.getLatestSuccess() for why this defaults to current time.
- latestSuccess = CurrentTimeUTC.get();
+ // See ClientRequester.getLatestSuccess() for why this defaults to current time.
+ latestSuccess = new Date();
failedBlocks = 0;
fatallyFailedBlocks = 0;
latestFailure = null;
@@ -242,7 +243,7 @@ public void completedBlock(boolean dontNotify, ClientContext context) {
synchronized(this) {
if(cancelled) return;
successfulBlocks++;
- latestSuccess = CurrentTimeUTC.get();
+ latestSuccess = new Date();
}
if(dontNotify) return;
notifyClients(context);
@@ -254,7 +255,7 @@ public void completedBlock(boolean dontNotify, ClientContext context) {
public void failedBlock(boolean dontNotify, ClientContext context) {
synchronized(this) {
failedBlocks++;
- latestFailure = CurrentTimeUTC.get();
+ latestFailure = new Date();
}
if(!dontNotify)
notifyClients(context);
@@ -269,7 +270,7 @@ public void failedBlock(ClientContext context) {
public void fatallyFailedBlock(ClientContext context) {
synchronized(this) {
fatallyFailedBlocks++;
- latestFailure = CurrentTimeUTC.get();
+ latestFailure = new Date();
}
notifyClients(context);
}
@@ -331,8 +332,8 @@ protected void clearCountersOnRestart() {
this.minSuccessBlocks = 0;
this.sentToNetwork = false;
this.successfulBlocks = 0;
- // See ClientRequester.getLatestSuccess() for why this defaults to current time.
- this.latestSuccess = CurrentTimeUTC.get();
+ // See ClientRequester.getLatestSuccess() for why this defaults to current time.
+ this.latestSuccess = new Date();
this.totalBlocks = 0;
}
diff --git a/src/freenet/client/async/HealingDecisionSupplier.java b/src/freenet/client/async/HealingDecisionSupplier.java
new file mode 100644
index 00000000000..e985cc976e3
--- /dev/null
+++ b/src/freenet/client/async/HealingDecisionSupplier.java
@@ -0,0 +1,85 @@
+package freenet.client.async;
+
+import java.util.function.Supplier;
+
+import freenet.node.Location;
+import freenet.node.NodeStarter;
+
+/**
+ * Specialize Healing to the fraction of the keyspace in which we would receive the inserts
+ * if we were one of 5 long distance nodes of an actual inserter.
+ *
+ * If an opennet node is connected to an attacker, healing traffic could be mistaken for an insert.
+ * Since opennet cannot be fully secured, this should be avoided.
+ * As a solution, we specialize healing inserts to the inserts we would send if we were one of 5
+ * long distance connections for a node in another part of the keyspace.
+ *
+ * As a welcome side effect, specialized healing inserts should take one hop less to reach the
+ * correct node from which loop detection will stop the insert long before HTL reaches zero.
+ */
+public class HealingDecisionSupplier {
+ private final Supplier currentNodeLocation;
+ private final Supplier isOpennetEnabled;
+ private final Supplier randomNumberSupplier;
+
+ public HealingDecisionSupplier(Supplier currentNodeLocation, Supplier isOpennetEnabled) {
+
+ this.currentNodeLocation = currentNodeLocation;
+ this.isOpennetEnabled = isOpennetEnabled;
+ randomNumberSupplier = NodeStarter.getGlobalSecureRandom()::nextDouble;
+ }
+
+ HealingDecisionSupplier(Supplier currentNodeLocation, Supplier isOpennetEnabled, Supplier randomNumberSupplier) {
+
+ this.currentNodeLocation = currentNodeLocation;
+ this.isOpennetEnabled = isOpennetEnabled;
+ this.randomNumberSupplier = randomNumberSupplier;
+ }
+
+ public boolean shouldHeal(double keyLocation) {
+ if (!isOpennetEnabled.get()) {
+ // darknet is safer against sybil attack, so we can heal fully
+ return true;
+ }
+ double randomBetweenZeroAndOne = randomNumberSupplier.get();
+ return shouldHealBlock(currentNodeLocation.get(), keyLocation, randomBetweenZeroAndOne);
+ }
+
+ /**
+ * Specialize healing: we want healing traffic to look like regular forwarding.
+ *
+ * Far away blocks would be unlikely to reach our node as request,
+ * so we reduce healing there: only accept 10% of those.
+ *
+ * When a key is close to our location, we use a continuous function depending on the distance
+ * to choose a probability. The closer to our node, the higher the probability of healing.
+ * As a side effect this reduces the hops healing inserts take, reducing the overall load
+ * on the network.
+ *
+ * The continuous function is gauged to accept 50% of the keys close to our node: a peak at our
+ * own location for which the area below the curve between 0 and 0.1 sums up to 0.5.
+ *
+ * Close keys are those in our 20% of the keyspace: the ones that would reach us if we were one of
+ * 5 long distance peers of a peer node. These are the keys for which we are most likely to be
+ * the best next hop when seen from the originator.
+ */
+ private static boolean shouldHealBlock(
+ double nodeLocation,
+ double keyLocation,
+ double randomBetweenZeroAndOne) {
+ double distanceToNodeLocation = Location.distance(nodeLocation, keyLocation);
+ // If the key is inside "our" 20% of the keyspace, heal it with 50% probability.
+ if (distanceToNodeLocation < 0.1) {
+ // accept 50%, specialized to our own location (0.5 ** 4 ~ 0.0625). Accept 70% which are going
+ // to our short distance peers (0.32 ** 4 ~ 0.01), 78% of those which could be reached via a
+ // direct short distance FOAF (distance 0.02).
+ double randomToPower4 = Math.pow(randomBetweenZeroAndOne, 4);
+ return distanceToNodeLocation < randomToPower4;
+ } else {
+ // if the key is a long distance key for us, heal it with 10% probability: it is unlikely that
+ // this would have reached us. Setting this to 0 could amplify a keyspace takeover attack.
+ return randomBetweenZeroAndOne > 0.9;
+ }
+ }
+
+}
diff --git a/src/freenet/client/async/InsertCompressor.java b/src/freenet/client/async/InsertCompressor.java
index 0827aa02d9c..0a18f8eeb61 100644
--- a/src/freenet/client/async/InsertCompressor.java
+++ b/src/freenet/client/async/InsertCompressor.java
@@ -1,5 +1,6 @@
package freenet.client.async;
+import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -106,9 +107,7 @@ public void tryCompress(final ClientContext context) throws InsertException {
boolean first = true;
long amountOfDataToCheckCompressionRatio = config.get("node").getLong("amountOfDataToCheckCompressionRatio");
int minimumCompressionPercentage = config.get("node").getInt("minimumCompressionPercentage");
- int maxTimeForSingleCompressor = config.get("node").getInt("maxTimeForSingleCompressor");
for (final COMPRESSOR_TYPE comp : comps) {
- long compressionStartTime = System.currentTimeMillis();
boolean shouldFreeOnFinally = true;
RandomAccessBucket result = null;
try {
@@ -215,9 +214,6 @@ public boolean run(ClientContext context) {
result.free();
}
- // if one iteration of compression took a lot of time, then we will not try other algorithms
- if (System.currentTimeMillis() - compressionStartTime > maxTimeForSingleCompressor)
- break;
}
final CompressionOutput output = new CompressionOutput(bestCompressedData, bestCodec, hashes);
diff --git a/src/freenet/client/async/KeyListenerTracker.java b/src/freenet/client/async/KeyListenerTracker.java
index 72efa9769dd..b62ff0a0443 100644
--- a/src/freenet/client/async/KeyListenerTracker.java
+++ b/src/freenet/client/async/KeyListenerTracker.java
@@ -6,13 +6,13 @@
import static java.lang.String.format;
import java.security.MessageDigest;
-import java.util.Arrays;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
-import java.util.List;
import freenet.crypt.RandomSource;
import freenet.crypt.SHA256;
@@ -20,7 +20,6 @@
import freenet.keys.KeyBlock;
import freenet.keys.NodeSSK;
import freenet.node.SendableGet;
-import freenet.node.SendableRequest;
import freenet.support.ByteArrayWrapper;
import freenet.support.LogThresholdCallback;
import freenet.support.Logger;
@@ -469,9 +468,7 @@ private byte[] saltKey(byte[] key) {
MessageDigest md = SHA256.getMessageDigest();
md.update(key);
md.update(globalSalt);
- byte[] ret = md.digest();
- SHA256.returnMessageDigest(md);
- return ret;
+ return md.digest();
}
protected void hintGlobalSalt(byte[] globalSalt2) {
diff --git a/src/freenet/client/async/PersistentStatsPutter.java b/src/freenet/client/async/PersistentStatsPutter.java
index c851bc8e09f..52dec29480c 100644
--- a/src/freenet/client/async/PersistentStatsPutter.java
+++ b/src/freenet/client/async/PersistentStatsPutter.java
@@ -37,7 +37,7 @@ public UptimeContainer getLatestUptimeData() {
public void updateData(Node n) {
// Update our values
// 0 : total bytes out, 1 : total bytes in
- final long[] nodeBW = n.collector.getTotalIO();
+ final long[] nodeBW = n.getCollector().getTotalIO();
this.latestBW.totalBytesOut += nodeBW[0] - this.latestNodeBytesOut;
this.latestBW.totalBytesIn += nodeBW[1] - this.latestNodeBytesIn;
this.latestBW.creationTime = System.currentTimeMillis();
diff --git a/src/freenet/client/async/SimpleHealingQueue.java b/src/freenet/client/async/SimpleHealingQueue.java
index d737b7348dd..63021acb47e 100644
--- a/src/freenet/client/async/SimpleHealingQueue.java
+++ b/src/freenet/client/async/SimpleHealingQueue.java
@@ -25,6 +25,7 @@ public class SimpleHealingQueue extends BaseClientPutter implements HealingQueue
final int maxRunning;
int counter;
InsertContext ctx;
+ private final HealingDecisionSupplier healingDecisionSupplier;
final Map runningInserters;
private static volatile boolean logMINOR;
@@ -39,9 +40,10 @@ public void shouldUpdate(){
static final RequestClient REQUEST_CLIENT = new RequestClientBuilder().build();
- public SimpleHealingQueue(InsertContext context, short prio, int maxRunning) {
+ public SimpleHealingQueue(InsertContext context, short prio, int maxRunning, HealingDecisionSupplier healingDecisionSupplier) {
super(prio, REQUEST_CLIENT);
this.ctx = context;
+ this.healingDecisionSupplier = healingDecisionSupplier;
this.runningInserters = new HashMap();
this.maxRunning = maxRunning;
}
@@ -60,7 +62,9 @@ public boolean innerQueue(Bucket data, byte[] cryptoKey, byte cryptoAlgorithm, C
Logger.error(this, "Caught trying to insert healing block: "+e, e);
return false;
}
- runningInserters.put(data, sbi);
+ if (isHealingThisBlockSimilarToForwarding(context, sbi)) {
+ runningInserters.put(data, sbi);
+ }
}
try {
sbi.schedule(context);
@@ -73,6 +77,15 @@ public boolean innerQueue(Bucket data, byte[] cryptoKey, byte cryptoAlgorithm, C
}
}
+ private boolean isHealingThisBlockSimilarToForwarding(
+ ClientContext context,
+ SingleBlockInserter sbi) {
+ // ensure that we have a routing key
+ sbi.tryEncode(context);
+ double keyLocation = sbi.getKeyNoEncode().getNodeKey().toNormalizedDouble();
+ return healingDecisionSupplier.shouldHeal(keyLocation);
+ }
+
@Override
public void queue(Bucket data, byte[] cryptoKey, byte cryptoAlgorithm, ClientContext context) {
if(!innerQueue(data, cryptoKey, cryptoAlgorithm, context))
diff --git a/src/freenet/client/async/SingleBlockInserter.java b/src/freenet/client/async/SingleBlockInserter.java
index e7f66b11abb..47d5a8292ee 100644
--- a/src/freenet/client/async/SingleBlockInserter.java
+++ b/src/freenet/client/async/SingleBlockInserter.java
@@ -497,15 +497,15 @@ public boolean run(ClientContext context) {
});
if(req.localRequestOnly)
try {
- core.node.store(b, false, req.canWriteClientCache, true, false);
+ core.getNode().store(b, false, req.canWriteClientCache, true, false);
} catch (KeyCollisionException e) {
LowLevelPutException failed = new LowLevelPutException(LowLevelPutException.COLLISION);
- KeyBlock collided = core.node.fetch(k.getNodeKey(), true, req.canWriteClientCache, false, false, null);
+ KeyBlock collided = core.getNode().fetch(k.getNodeKey(), true, req.canWriteClientCache, false, false, null);
if(collided == null) {
Logger.error(this, "Collided but no key?!");
// Could be a race condition.
try {
- core.node.store(b, false, req.canWriteClientCache, true, false);
+ core.getNode().store(b, false, req.canWriteClientCache, true, false);
} catch (KeyCollisionException e2) {
Logger.error(this, "Collided but no key and still collided!");
throw new LowLevelPutException(LowLevelPutException.INTERNAL_ERROR, "Collided, can't find block, but still collides!", e);
diff --git a/src/freenet/client/async/SingleFileFetcher.java b/src/freenet/client/async/SingleFileFetcher.java
index 4df09b31b9e..05307c8e28e 100644
--- a/src/freenet/client/async/SingleFileFetcher.java
+++ b/src/freenet/client/async/SingleFileFetcher.java
@@ -349,7 +349,7 @@ private synchronized void handleMetadata(final ClientContext context) throws Fet
return;
}
}
- if(metaStrings.size() == 0) {
+ if(metaStrings.isEmpty()) {
if(metadata.hasTopData()) {
if((metadata.topSize > ctx.maxOutputLength) ||
(metadata.topCompressedSize > ctx.maxTempLength)) {
@@ -375,7 +375,7 @@ private synchronized void handleMetadata(final ClientContext context) throws Fet
} else if(metaStrings.isEmpty()) {
FreenetURI u = uri;
String last = u.lastMetaString();
- if(last == null || !last.equals(""))
+ if(last == null || !last.isEmpty())
u = u.addMetaStrings(new String[] { "" });
else
u = null;
@@ -653,7 +653,7 @@ public boolean run(ClientContext context) {
}
String mimeType = clientMetadata.getMIMETypeNoParams();
- if(mimeType != null && ArchiveManager.ARCHIVE_TYPE.isUsableArchiveType(mimeType) && metaStrings.size() > 0) {
+ if(mimeType != null && ArchiveManager.ARCHIVE_TYPE.isUsableArchiveType(mimeType) && !metaStrings.isEmpty()) {
// Looks like an implicit archive, handle as such
metadata.setArchiveManifest();
// Pick up MIME type from inside archive
@@ -728,7 +728,7 @@ public boolean run(ClientContext context) {
clientMetadata.mergeNoOverwrite(metadata.getClientMetadata()); // even splitfiles can have mime types!
String mimeType = clientMetadata.getMIMETypeNoParams();
- if(mimeType != null && ArchiveManager.ARCHIVE_TYPE.isUsableArchiveType(mimeType) && metaStrings.size() > 0) {
+ if(mimeType != null && ArchiveManager.ARCHIVE_TYPE.isUsableArchiveType(mimeType) && !metaStrings.isEmpty()) {
// Looks like an implicit archive, handle as such
metadata.setArchiveManifest();
// Pick up MIME type from inside archive
@@ -1276,11 +1276,12 @@ public int hashCode() {
@Override
public void onFoundEdition(long l, USK newUSK, ClientContext context, boolean metadata, short codec, byte[] data, boolean newKnownGood, boolean newSlotToo) {
- if(l < usk.suggestedEdition && datastoreOnly)
+ if(l < usk.suggestedEdition && datastoreOnly) {
l = usk.suggestedEdition;
+ }
ClientSSK key = usk.getSSK(l);
try {
- if(l == usk.suggestedEdition) {
+ if(l == usk.suggestedEdition || (l == 0 && usk.suggestedEdition == 1)) {
SingleFileFetcher sf = new SingleFileFetcher(parent, cb, null, key, metaStrings, key.getURI().addMetaStrings(metaStrings),
0, ctx, false, realTimeFlag, actx, null, null, maxRetries, recursionLevel+1, dontTellClientGet, token, false, true, false, (short)0, context, false);
if(tag != null) {
diff --git a/src/freenet/client/async/SplitFileFetcher.java b/src/freenet/client/async/SplitFileFetcher.java
index d35418b4836..f2ef033bada 100644
--- a/src/freenet/client/async/SplitFileFetcher.java
+++ b/src/freenet/client/async/SplitFileFetcher.java
@@ -21,6 +21,7 @@
import freenet.keys.FreenetURI;
import freenet.node.BaseSendableGet;
import freenet.support.Logger;
+import freenet.support.api.Bucket;
import freenet.support.api.LockableRandomAccessBuffer;
import freenet.support.compress.Compressor.COMPRESSOR_TYPE;
import freenet.support.io.BucketTools;
@@ -125,7 +126,7 @@ public SplitFileFetcher(Metadata metadata, GetCompletionCallback rcb, ClientRequ
try {
// Completion via truncation.
if(isFinalFetch && cb instanceof FileGetCompletionCallback &&
- (decompressors == null || decompressors.size() == 0) &&
+ (decompressors == null || decompressors.isEmpty()) &&
!fetchContext.filterData) {
FileGetCompletionCallback fileCallback = ((FileGetCompletionCallback)cb);
File targetFile = fileCallback.getCompletionFile();
@@ -297,7 +298,10 @@ public void onSplitfileCompatibilityMode(CompatibilityMode min, CompatibilityMod
@Override
public void queueHeal(byte[] data, byte[] cryptoKey, byte cryptoAlgorithm) {
try {
- context.healingQueue.queue(BucketTools.makeImmutableBucket(context.tempBucketFactory, data), cryptoKey, cryptoAlgorithm, context);
+ Bucket dataBucket = BucketTools.makeImmutableBucket(
+ context.tempBucketFactory,
+ data);
+ context.healingQueue.queue(dataBucket, cryptoKey, cryptoAlgorithm, context);
} catch (IOException e) {
// Nothing to be done, but need to log the error.
Logger.error(this, "I/O error, failed to queue healing block: "+e, e);
diff --git a/src/freenet/client/async/SplitFileFetcherKeyListener.java b/src/freenet/client/async/SplitFileFetcherKeyListener.java
index 656b1a28e47..339c36691c1 100644
--- a/src/freenet/client/async/SplitFileFetcherKeyListener.java
+++ b/src/freenet/client/async/SplitFileFetcherKeyListener.java
@@ -204,9 +204,7 @@ private byte[] localSaltKey(Key key) {
MessageDigest md = SHA256.getMessageDigest();
md.update(key.getRoutingKey());
md.update(localSalt);
- byte[] ret = md.digest();
- SHA256.returnMessageDigest(md);
- return ret;
+ return md.digest();
}
/** The segment bloom filters should only need to be written ONCE, and can all be written at
diff --git a/src/freenet/client/async/SplitFileInserterSender.java b/src/freenet/client/async/SplitFileInserterSender.java
index cbc3cb413ea..eefee5899f1 100644
--- a/src/freenet/client/async/SplitFileInserterSender.java
+++ b/src/freenet/client/async/SplitFileInserterSender.java
@@ -136,7 +136,7 @@ public boolean run(ClientContext context) {
});
if(request.localRequestOnly) {
try {
- node.node.store(block, false, request.canWriteClientCache, true, false);
+ node.getNode().store(block, false, request.canWriteClientCache, true, false);
} catch (KeyCollisionException e) {
throw new LowLevelPutException(LowLevelPutException.COLLISION);
}
diff --git a/src/freenet/client/async/USKFetcher.java b/src/freenet/client/async/USKFetcher.java
index 803a7d84e2c..46bb7af7d46 100644
--- a/src/freenet/client/async/USKFetcher.java
+++ b/src/freenet/client/async/USKFetcher.java
@@ -6,9 +6,15 @@
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MINUTES;
-import java.io.*;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -16,10 +22,10 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeMap;
import java.util.TreeSet;
-import java.util.Map.Entry;
import freenet.client.ClientMetadata;
import freenet.client.FetchContext;
@@ -46,8 +52,8 @@
import freenet.node.SendableRequestItem;
import freenet.support.LogThresholdCallback;
import freenet.support.Logger;
-import freenet.support.RemoveRangeArrayList;
import freenet.support.Logger.LogLevel;
+import freenet.support.RemoveRangeArrayList;
import freenet.support.api.Bucket;
import freenet.support.compress.Compressor;
import freenet.support.compress.DecompressorThreadManager;
@@ -266,10 +272,7 @@ private void innerSuccess(Bucket bucket,
}
String line;
try {
- line = new String(data, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- Logger.error(this, "Impossible: "+e, e);
- return;
+ line = new String(data, StandardCharsets.UTF_8);
} catch (Throwable t) {
// Something very bad happened, most likely bogus encoding.
// Ignore it.
@@ -1543,7 +1546,7 @@ protected ClientGetState getClientGetState() {
return USKFetcher.this;
}
- };
+ }
@Override
@@ -1727,8 +1730,14 @@ public synchronized ToFetch getEditionsToFetch(long lookedUp, Random random, Lis
for(Iterator> it = fromSubscribers.entrySet().iterator();it.hasNext();) {
Entry entry = it.next();
long l = entry.getKey() - 1;
- if(l <= lookedUp)
+ if(l <= lookedUp) {
it.remove();
+ }
+ if (l == 0) {
+ // add check for edition 0: this happens if -1 is suggested.
+ // Needed because we cannot set -0 for exhaustive search (-0 == 0 in Java).
+ entry.getValue().getEditionIfNotAlreadyRunning(toFetch, alreadyRunning, l, false);
+ }
entry.getValue().getNextEditions(toFetch, toPoll, l-1, alreadyRunning, random);
}
@@ -1835,63 +1844,63 @@ public KeyList(long slot) {
public synchronized void getNextEditions(List toFetch, List toPoll, long lookedUp, List alreadyRunning, Random random) {
if(logMINOR) Logger.minor(this, "Getting next editions from "+lookedUp);
if(lookedUp < 0) lookedUp = 0;
+ boolean poll = backgroundPoll;
for(int i=1;i<=origMinFailures;i++) {
long ed = i + lookedUp;
+ if (poll) {
+ getEditionIfNotAlreadyRunning(toPoll, alreadyRunning, ed, true);
+ } else {
+ getEditionIfNotAlreadyRunning(toFetch, alreadyRunning, ed, true);
+ }
+ }
+ }
+
+ /** @return whether the edition was added. */
+ public boolean getEditionIfNotAlreadyRunning(
+ List lookupList,
+ List alreadyRunning,
+ long ed,
+ boolean ignoreStore) {
Lookup l = new Lookup();
l.val = ed;
- boolean poll = backgroundPoll;
- if(((!poll) && toFetch.contains(l)) || (poll && toPoll.contains(l))) {
+ if(lookupList.contains(l)) {
if(logDEBUG) Logger.debug(this, "Ignoring "+l);
- continue;
+ return false;
}
if(alreadyRunning.remove(l)) {
if(logDEBUG) Logger.debug(this, "Ignoring (2): "+l);
- continue;
+ return false;
}
ClientSSK key;
// FIXME reuse ehDocnames somehow
// The problem is we need a ClientSSK for the high level stuff.
key = origUSK.getSSK(ed);
l.key = key;
- l.ignoreStore = true;
- if(poll) {
- if(!toPoll.contains(l)) {
- toPoll.add(l);
- } else {
- if(logDEBUG) Logger.debug(this, "Ignoring poll (3): "+l);
- }
- } else {
- if(!toFetch.contains(l)) {
- toFetch.add(l);
- } else {
- if(logDEBUG) Logger.debug(this, "Ignoring fetch (3): "+l);
- }
- }
+ l.ignoreStore = ignoreStore;
+ if(lookupList.contains(l)) {
+ if (logDEBUG) Logger.debug(this, "Ignoring (3): " + l);
+ return false;
}
+ return lookupList.add(l);
}
public synchronized void getRandomEditions(List toFetch, long lookedUp, List alreadyRunning, Random random, int allowed) {
// Then add a couple of random editions for catch-up.
long baseEdition = lookedUp + origMinFailures;
for(int i=0;i= WATCH_KEYS);
- toFetch.add(l);
if(logMINOR) Logger.minor(this, "Trying random future edition "+fetch+" for "+origUSK+" current edition "+lookedUp);
+ if (getEditionIfNotAlreadyRunning(toFetch, alreadyRunning, fetch, !(fetch - lookedUp >= WATCH_KEYS))) {
break;
}
}
}
+ }
public class StoreSubChecker {
@@ -2067,7 +2076,7 @@ public synchronized USKStoreChecker getDatastoreChecker(long lastSlot) {
c = entry.getValue().checkStore(l);
if(c != null) checkers.add(c);
}
- if(checkers.size() > 0)
+ if(!checkers.isEmpty())
return new USKStoreChecker(checkers);
else return null;
}
diff --git a/src/freenet/client/async/USKInserter.java b/src/freenet/client/async/USKInserter.java
index e479b014b1e..af22aed62ac 100644
--- a/src/freenet/client/async/USKInserter.java
+++ b/src/freenet/client/async/USKInserter.java
@@ -5,8 +5,8 @@
import java.io.IOException;
import java.io.Serializable;
-import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import freenet.client.InsertContext;
@@ -152,12 +152,7 @@ private void insertSucceeded(ClientContext context, long edition) {
if(logMINOR) Logger.minor(this, "Inserted to edition "+edition+" - inserting USK date hints...");
USKDateHint hint = USKDateHint.now();
MultiPutCompletionCallback m = new MultiPutCompletionCallback(cb, parent, tokenObject, persistent, true);
- byte[] hintData;
- try {
- hintData = hint.getData(edition).getBytes("UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new Error(e); // Impossible
- }
+ byte[] hintData = hint.getData(edition).getBytes(StandardCharsets.UTF_8);
FreenetURI[] hintURIs = hint.getInsertURIs(privUSK);
boolean added = false;
for(FreenetURI uri : hintURIs) {
diff --git a/src/freenet/client/async/USKManager.java b/src/freenet/client/async/USKManager.java
index 0fd20242b6d..80c1107175b 100644
--- a/src/freenet/client/async/USKManager.java
+++ b/src/freenet/client/async/USKManager.java
@@ -126,7 +126,7 @@ public void init(ClientContext context) {
public synchronized long lookupKnownGood(USK usk) {
Long l = latestKnownGoodByClearUSK.get(usk.clearCopy());
if(l != null)
- return l.longValue();
+ return l;
else return -1;
}
@@ -138,7 +138,7 @@ public synchronized long lookupKnownGood(USK usk) {
public synchronized long lookupLatestSlot(USK usk) {
Long l = latestSlotByClearUSK.get(usk.clearCopy());
if(l != null)
- return l.longValue();
+ return l;
else return -1;
}
@@ -431,8 +431,8 @@ void updateKnownGood(final USK origUSK, final long number, final ClientContext c
synchronized(this) {
Long l = latestKnownGoodByClearUSK.get(clear);
if(logMINOR) Logger.minor(this, "Old known good: "+l);
- if((l == null) || (number > l.longValue())) {
- l = Long.valueOf(number);
+ if((l == null) || (number > l)) {
+ l = number;
latestKnownGoodByClearUSK.put(clear, l);
if(logMINOR) Logger.minor(this, "Put "+number);
} else
@@ -440,8 +440,8 @@ void updateKnownGood(final USK origUSK, final long number, final ClientContext c
l = latestSlotByClearUSK.get(clear);
if(logMINOR) Logger.minor(this, "Old slot: "+l);
- if((l == null) || (number > l.longValue())) {
- l = Long.valueOf(number);
+ if((l == null) || (number > l)) {
+ l = number;
latestSlotByClearUSK.put(clear, l);
if(logMINOR) Logger.minor(this, "Put "+number);
newSlot = true;
@@ -471,8 +471,8 @@ void updateSlot(final USK origUSK, final long number, final ClientContext contex
synchronized(this) {
Long l = latestSlotByClearUSK.get(clear);
if(logMINOR) Logger.minor(this, "Old slot: "+l);
- if((l == null) || (number > l.longValue())) {
- l = Long.valueOf(number);
+ if((l == null) || (number > l)) {
+ l = number;
latestSlotByClearUSK.put(clear, l);
if(logMINOR) Logger.minor(this, "Put "+number);
} else
diff --git a/src/freenet/client/events/ClientEventProducer.java b/src/freenet/client/events/ClientEventProducer.java
index 86bfeac3442..d12484829e6 100644
--- a/src/freenet/client/events/ClientEventProducer.java
+++ b/src/freenet/client/events/ClientEventProducer.java
@@ -27,7 +27,7 @@ public interface ClientEventProducer {
void addEventListener(ClientEventListener cel);
/**
- * Removes an EventListener that will no loger receive events
+ * Removes an EventListener that will no longer receive events
* produced by the implementing object.
* @param cel The ClientEventListener to remove.
* @return true if a Listener was removed, false otherwise.
diff --git a/src/freenet/client/events/SplitfileProgressEvent.java b/src/freenet/client/events/SplitfileProgressEvent.java
index 12086627722..5063130e61d 100644
--- a/src/freenet/client/events/SplitfileProgressEvent.java
+++ b/src/freenet/client/events/SplitfileProgressEvent.java
@@ -6,7 +6,6 @@
import java.util.Date;
import freenet.client.async.ClientRequester;
-import freenet.support.CurrentTimeUTC;
import freenet.support.LogThresholdCallback;
import freenet.support.Logger;
import freenet.support.Logger.LogLevel;
@@ -61,7 +60,7 @@ protected SplitfileProgressEvent() {
totalBlocks = 0;
succeedBlocks = 0;
// See ClientRequester.getLatestSuccess() for why this defaults to current time.
- latestSuccess = CurrentTimeUTC.get();
+ latestSuccess = new Date();
failedBlocks = 0;
fatallyFailedBlocks = 0;
latestFailure = null;
diff --git a/src/freenet/client/filter/CSSTokenizerFilter.java b/src/freenet/client/filter/CSSTokenizerFilter.java
index 9a0556470b2..a6e47a76d92 100644
--- a/src/freenet/client/filter/CSSTokenizerFilter.java
+++ b/src/freenet/client/filter/CSSTokenizerFilter.java
@@ -3,9 +3,14 @@
* http://www.gnu.org/ for further details of the GPL. */
package freenet.client.filter;
+
+import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
+import java.net.URI;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
@@ -22,11 +27,6 @@
import freenet.support.api.Bucket;
import freenet.support.io.FileBucket;
-import java.io.File;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-
/** Comprehensive CSS2.1 filter. The old jflex-based filter was very far
* from comprehensive.
* @author kurmiashish
@@ -118,6 +118,7 @@ public static T[] concat(T[] a, T[] b) {
allelementVerifiers.add("align-self");
allelementVerifiers.add("azimuth");
allelementVerifiers.add("background-attachment");
+ allelementVerifiers.add("background-blend-mode");
allelementVerifiers.add("background-clip");
allelementVerifiers.add("background-color");
allelementVerifiers.add("background-image");
@@ -126,6 +127,7 @@ public static T[] concat(T[] a, T[] b) {
allelementVerifiers.add("background-repeat");
allelementVerifiers.add("background-size");
allelementVerifiers.add("background");
+ allelementVerifiers.add("block-size");
allelementVerifiers.add("border-collapse");
allelementVerifiers.add("border-color");
allelementVerifiers.add("border-top-color");
@@ -204,6 +206,7 @@ public static T[] concat(T[] a, T[] b) {
allelementVerifiers.add("cursor");
allelementVerifiers.add("direction");
allelementVerifiers.add("display");
+ allelementVerifiers.add("dominant-baseline");
allelementVerifiers.add("elevation");
allelementVerifiers.add("empty-cells");
allelementVerifiers.add("flex");
@@ -215,6 +218,7 @@ public static T[] concat(T[] a, T[] b) {
allelementVerifiers.add("flex-wrap");
allelementVerifiers.add("float");
allelementVerifiers.add("font-family");
+ allelementVerifiers.add("font-kerning");
allelementVerifiers.add("font-size");
allelementVerifiers.add("font-style");
allelementVerifiers.add("font-variant");
@@ -222,6 +226,7 @@ public static T[] concat(T[] a, T[] b) {
allelementVerifiers.add("font");
allelementVerifiers.add("hanging-punctuation");
allelementVerifiers.add("height");
+ allelementVerifiers.add("inline-size");
allelementVerifiers.add("justify-content");
allelementVerifiers.add("justify-items");
allelementVerifiers.add("justify-self");
@@ -238,14 +243,20 @@ public static T[] concat(T[] a, T[] b) {
allelementVerifiers.add("margin-top");
allelementVerifiers.add("margin-bottom");
allelementVerifiers.add("margin");
+ allelementVerifiers.add("max-block-size");
allelementVerifiers.add("max-height");
+ allelementVerifiers.add("max-inline-size");
allelementVerifiers.add("max-width");
+ allelementVerifiers.add("min-block-size");
allelementVerifiers.add("min-height");
+ allelementVerifiers.add("min-inline-size");
allelementVerifiers.add("min-width");
+ allelementVerifiers.add("mix-blend-mode");
allelementVerifiers.add("nav-down");
allelementVerifiers.add("nav-left");
allelementVerifiers.add("nav-right");
allelementVerifiers.add("nav-up");
+ allelementVerifiers.add("object-fit");
allelementVerifiers.add("opacity");
allelementVerifiers.add("order");
allelementVerifiers.add("orphans");
@@ -255,6 +266,7 @@ public static T[] concat(T[] a, T[] b) {
allelementVerifiers.add("outline-width");
allelementVerifiers.add("outline");
allelementVerifiers.add("overflow");
+ allelementVerifiers.add("overflow-wrap");
allelementVerifiers.add("padding-top");
allelementVerifiers.add("padding-right");
allelementVerifiers.add("padding-bottom");
@@ -282,14 +294,17 @@ public static T[] concat(T[] a, T[] b) {
allelementVerifiers.add("speech-rate");
allelementVerifiers.add("stress");
allelementVerifiers.add("table-layout");
+ allelementVerifiers.add("tab-size");
allelementVerifiers.add("text-align");
allelementVerifiers.add("text-align-last");
allelementVerifiers.add("text-autospace");
+ allelementVerifiers.add("text-combine-upright");
allelementVerifiers.add("text-decoration");
allelementVerifiers.add("text-decoration-color");
allelementVerifiers.add("text-decoration-line");
allelementVerifiers.add("text-decoration-skip");
allelementVerifiers.add("text-decoration-style");
+ allelementVerifiers.add("text-decoration-thickness");
allelementVerifiers.add("text-emphasis");
allelementVerifiers.add("text-emphasis-color");
allelementVerifiers.add("text-emphasis-position");
@@ -315,12 +330,13 @@ public static T[] concat(T[] a, T[] b) {
allelementVerifiers.add("voice-family");
allelementVerifiers.add("volume");
allelementVerifiers.add("white-space");
- allelementVerifiers.add("white-space-collapsing");
+ allelementVerifiers.add("white-space-collapse");
allelementVerifiers.add("widows");
allelementVerifiers.add("width");
allelementVerifiers.add("word-break");
allelementVerifiers.add("word-spacing");
allelementVerifiers.add("word-wrap");
+ allelementVerifiers.add("writing-mode");
allelementVerifiers.add("z-index");
@@ -330,7 +346,7 @@ public static T[] concat(T[] a, T[] b) {
* Array for storing additional Verifier objects for validating Regular expressions in CSS Property value
* e.g. [ | transparent]{1,4}. It is explained in detail in CSSPropertyVerifier class
*/
- private final static CSSPropertyVerifier[] auxilaryVerifiers=new CSSPropertyVerifier[148];
+ private final static CSSPropertyVerifier[] auxilaryVerifiers=new CSSPropertyVerifier[149];
static
{
/*CSSPropertyVerifier(String[] allowedValues,String[] possibleValues,String expression,boolean onlyValueVerifier)*/
@@ -348,15 +364,20 @@ public static T[] concat(T[] a, T[] b) {
//
auxilaryVerifiers[15]=new CSSPropertyVerifier(Arrays.asList("transparent"),Arrays.asList("co"),null,null,true);
+ //list-style-type
+ auxilaryVerifiers[35]=new CSSPropertyVerifier(Arrays.asList("disc","circle","square","decimal","decimal-leading-zero","lower-roman","upper-roman","lower-greek","lower-latin","upper-latin","armenian","georgian","lower-alpha","upper-alpha","none","arabic-indic","bengali","cambodian","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","devanagari","disclosure-closed","disclosure-open","ethiopic-numeric","gujarati","gurmukhi","hebrew","hiragana","hiragana-iroha","japanese-formal","japanese-informal","kannada","katakana","katakana-iroha","khmer","korean-hangul-formal","korean-hanja-formal","lao","lower-armenian","malayalam","mongolian","myanmar","oriya","persian","simp-chinese-formal","simp-chinese-informal","tamil","telugu","thai","tibetan","trad-chinese-formal","trad-chinese-informal","upper-armenian"),Arrays.asList("st"),null,null,true);
+
//
auxilaryVerifiers[61]=new CSSPropertyVerifier(Arrays.asList("border-box", "padding-box", "content-box"),null,null,null,true);
//
auxilaryVerifiers[64]=new CSSPropertyVerifier(null,Arrays.asList("le", "pe"),null,null,true);
+ //
+ auxilaryVerifiers[73]=new CSSPropertyVerifier(null, Arrays.asList("co"), null, null, true);
+
//
auxilaryVerifiers[71]=new CSSPropertyVerifier(Arrays.asList("inset"), null, null, null, true);
auxilaryVerifiers[72]=new CSSPropertyVerifier(null, Arrays.asList("le"), null, null, true);
- auxilaryVerifiers[73]=new CSSPropertyVerifier(null, Arrays.asList("co"), null, null, true);
auxilaryVerifiers[74]=new CSSPropertyVerifier(null, null, Arrays.asList("72<1,4>"), null, true);
auxilaryVerifiers[75]=new CSSPropertyVerifier(null, null, Arrays.asList("71a74a73"), null, true);
@@ -372,7 +393,7 @@ public static T[] concat(T[] a, T[] b) {
auxilaryVerifiers[78]=new CSSPropertyVerifier(null,null,Arrays.asList("70<1,2>"),null,true);
//
- auxilaryVerifiers[79]=new CSSPropertyVerifier(null, null, Arrays.asList("74a73"), null, true);
+ auxilaryVerifiers[79]=new CSSPropertyVerifier(null, null, Arrays.asList("73 72 72 72","73 72 72","72 72 72 73","72 72 73","72 72"), null, true);
//
auxilaryVerifiers[85]=new CSSPropertyVerifier(Arrays.asList("normal"), Arrays.asList("le","pe"), null, null, true);
@@ -383,15 +404,13 @@ public static T[] concat(T[] a, T[] b) {
auxilaryVerifiers[102] = new CSSPropertyVerifier(Arrays.asList("line-through"), null, null, null, true);
auxilaryVerifiers[115] = new CSSPropertyVerifier(Arrays.asList("none"),null,null,Arrays.asList("100a101a102"));
auxilaryVerifiers[116] = new CSSPropertyVerifier(Arrays.asList("blink"), null, null, null, true);
- //
- auxilaryVerifiers[103] = new CSSPropertyVerifier(null, Arrays.asList("co"), null, null, true);
//
auxilaryVerifiers[104] = new CSSPropertyVerifier(Arrays.asList("solid", "double", "dotted", "dashed", "wave"), null, null, null, true);
//
auxilaryVerifiers[105]=new CSSPropertyVerifier(Arrays.asList("filled","open"),null,null,null,true);
auxilaryVerifiers[106]=new CSSPropertyVerifier(Arrays.asList("dot","circle","double-circle","triangle","sesame"),null,null,null,true);
- auxilaryVerifiers[107]=new CSSPropertyVerifier(Arrays.asList("none"),ElementInfo.VISUALMEDIA,Arrays.asList("st"),Arrays.asList("105a106"));
+ auxilaryVerifiers[107]=new CSSPropertyVerifier(Arrays.asList("none"),null,Arrays.asList("st"),Arrays.asList("105a106"));
// and
// auto | | || [ ? && ]
@@ -453,6 +472,11 @@ else if("background-attachment".equalsIgnoreCase(element)){
elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("60<1,65535>"), true,true));
allelementVerifiers.remove(element);
}
+ else if("background-blend-mode".equalsIgnoreCase(element)){
+ auxilaryVerifiers[148] = new CSSPropertyVerifier(Arrays.asList("normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"), null, null, null, true);
+ elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("148<1,2>"), true,true));
+ allelementVerifiers.remove(element);
+ }
else if("background-clip".equalsIgnoreCase(element))
{
elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("61<1,65535>"), true,true));
@@ -511,6 +535,11 @@ else if("background".equalsIgnoreCase(element))
elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("6a7a8a9a10")));
allelementVerifiers.remove(element);
}
+ else if("block-size".equalsIgnoreCase(element))
+ {
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("auto"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
+ allelementVerifiers.remove(element);
+ }
else if("border-collapse".equalsIgnoreCase(element))
{
elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("collapse","separate"),ElementInfo.VISUALMEDIA));
@@ -774,12 +803,12 @@ else if("caption-side".equalsIgnoreCase(element))
allelementVerifiers.remove(element);
} else if ("caret-color".equalsIgnoreCase(element)) {
- elementVerifiers.put(element, new CSSPropertyVerifier(Arrays.asList("auto", "transparent"), ElementInfo.VISUALMEDIA, Arrays.asList("co")));
+ elementVerifiers.put(element, new CSSPropertyVerifier(Arrays.asList("auto", "transparent", "currentcolor"), ElementInfo.VISUALMEDIA, Arrays.asList("co")));
allelementVerifiers.remove(element);
}
else if("clear".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("none","left","right","both"),ElementInfo.VISUALMEDIA));
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("none","left","right","both","inline-start","inline-end"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
else if("clip".equalsIgnoreCase(element))
@@ -975,6 +1004,11 @@ else if("display".equalsIgnoreCase(element))
elementVerifiers.put(element,new CSSPropertyVerifier(null, null, Arrays.asList("131a132", "140<0,1>[1,3]", "137", "138", "139"), null, true));
allelementVerifiers.remove(element);
}
+ else if("dominant-baseline".equalsIgnoreCase(element))
+ {
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("auto", "text-bottom", "alphabetic", "ideographic", "middle", "central", "mathematical", "hanging", "text-top"),ElementInfo.VISUALMEDIA));
+ allelementVerifiers.remove(element);
+ }
else if("elevation".equalsIgnoreCase(element))
{
elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("below","level","above","higher","lower"),ElementInfo.AURALMEDIA,Arrays.asList("an")));
@@ -987,7 +1021,7 @@ else if("empty-cells".equalsIgnoreCase(element))
}
else if("float".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("left","right","none"),ElementInfo.VISUALMEDIA));
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("left","right","none","inline-start","inline-end"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
} else if ("flex".equalsIgnoreCase(element)) {
// flex: none | ? ||
@@ -1026,9 +1060,14 @@ else if("font-family".equalsIgnoreCase(element))
elementVerifiers.put(element,new FontPropertyVerifier(false));
allelementVerifiers.remove(element);
}
+ else if("font-kerning".equalsIgnoreCase(element))
+ {
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("auto","none","normal"),ElementInfo.VISUALMEDIA));
+ allelementVerifiers.remove(element);
+ }
else if("font-size".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("xx-small","x-small","small","medium","large","x-large","xx-large","larger","smaller"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("xx-small","x-small","small","medium","large","x-large","xx-large","xxx-large","larger","smaller"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
allelementVerifiers.remove(element);
}
else if("font-style".equalsIgnoreCase(element))
@@ -1089,6 +1128,11 @@ else if("hanging-punctuation".equalsIgnoreCase(element))
allelementVerifiers.remove(element);
}
else if("height".equalsIgnoreCase(element))
+ {
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("auto"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
+ allelementVerifiers.remove(element);
+ }
+ else if("inline-size".equalsIgnoreCase(element))
{
elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("auto"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
allelementVerifiers.remove(element);
@@ -1119,7 +1163,7 @@ else if("line-height".equalsIgnoreCase(element))
}
else if("line-break".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("auto","newspaper","normal","strict","keep-all"),ElementInfo.VISUALMEDIA));
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("auto","anywhere","normal","strict","loose"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
else if("list-style-image".equalsIgnoreCase(element))
@@ -1134,7 +1178,7 @@ else if("list-style-position".equalsIgnoreCase(element))
}
else if("list-style-type".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("disc","circle","square","decimal","decimal-leading-zero","lower-roman","upper-roman","lower-greek","lower-latin","upper-latin","armenian","georgian","lower-alpha","upper-alpha","none"),ElementInfo.VISUALMEDIA));
+ elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("35")));
allelementVerifiers.remove(element);
}
else if("list-style".equalsIgnoreCase(element))
@@ -1143,8 +1187,6 @@ else if("list-style".equalsIgnoreCase(element))
auxilaryVerifiers[33]=new CSSPropertyVerifier(Arrays.asList("none"),Arrays.asList("ur"),null,null,true);
//list-style-position
auxilaryVerifiers[34]=new CSSPropertyVerifier(Arrays.asList("inside","outside"),null,null,null,true);
- //list-style-type
- auxilaryVerifiers[35]=new CSSPropertyVerifier(Arrays.asList("disc","circle","square","decimal","decimal-leading-zero","lower-roman","upper-roman","lower-greek","lower-latin","upper-latin","armenian","georgian","lower-alpha","upper-alpha","none"),null,null,null,true);
elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("33a34a35")));
allelementVerifiers.remove(element);
}
@@ -1176,26 +1218,52 @@ else if("margin".equalsIgnoreCase(element))
elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("36<1,4>")));
allelementVerifiers.remove(element);
}
+ else if("max-block-size".equalsIgnoreCase(element))
+ {
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("none"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
+ allelementVerifiers.remove(element);
+ }
else if("max-height".equalsIgnoreCase(element))
{
elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("none"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
allelementVerifiers.remove(element);
}
+ else if("max-inline-size".equalsIgnoreCase(element))
+ {
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("none"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
+ allelementVerifiers.remove(element);
+ }
else if("max-width".equalsIgnoreCase(element))
{
elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("none"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
allelementVerifiers.remove(element);
}
+ else if("min-block-size".equalsIgnoreCase(element))
+ {
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("auto"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
+ allelementVerifiers.remove(element);
+ }
else if("min-height".equalsIgnoreCase(element))
{
elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("auto"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
allelementVerifiers.remove(element);
}
+ else if("min-inline-size".equalsIgnoreCase(element))
+ {
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("auto"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
+ allelementVerifiers.remove(element);
+ }
else if("min-width".equalsIgnoreCase(element))
{
elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("auto"),ElementInfo.VISUALMEDIA,Arrays.asList("le","pe")));
allelementVerifiers.remove(element);
- } else if ("nav-down".equalsIgnoreCase(element)) {
+ }
+ else if("mix-blend-mode".equalsIgnoreCase(element)){
+ auxilaryVerifiers[148] = new CSSPropertyVerifier(Arrays.asList("normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"), null, null, null, true);
+ elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("148<1,2>"), true,true));
+ allelementVerifiers.remove(element);
+ }
+ else if ("nav-down".equalsIgnoreCase(element)) {
elementVerifiers.put(element, new CSSPropertyVerifier(Arrays.asList("auto"), ElementInfo.VISUALINTERACTIVEMEDIA, null, Arrays.asList("143 144?")));
allelementVerifiers.remove(element);
} else if ("nav-left".equalsIgnoreCase(element)) {
@@ -1207,6 +1275,9 @@ else if("min-width".equalsIgnoreCase(element))
} else if ("nav-up".equalsIgnoreCase(element)) {
elementVerifiers.put(element, new CSSPropertyVerifier(Arrays.asList("auto"), ElementInfo.VISUALINTERACTIVEMEDIA, null, Arrays.asList("143 144?")));
allelementVerifiers.remove(element);
+ } else if ("object-fit".equalsIgnoreCase(element)) {
+ elementVerifiers.put(element, new CSSPropertyVerifier(Arrays.asList("contain","cover","fill","none","scale-down"), ElementInfo.VISUALMEDIA));
+ allelementVerifiers.remove(element);
}
else if("opacity".equalsIgnoreCase(element))
{
@@ -1252,7 +1323,7 @@ else if("outline".equalsIgnoreCase(element))
}
else if("overflow".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("visible","hidden","scroll","auto"),ElementInfo.VISUALMEDIA));
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("visible","hidden","scroll","auto","clip"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
else if("padding-top".equalsIgnoreCase(element))
@@ -1410,6 +1481,11 @@ else if("table-layout".equalsIgnoreCase(element))
elementVerifiers.put(element,new CSSPropertyVerifier( Arrays.asList("auto","fixed"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
+ else if("tab-size".equalsIgnoreCase(element))
+ {
+ elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,Arrays.asList("le","in")));
+ allelementVerifiers.remove(element);
+ }
else if("text-align".equalsIgnoreCase(element))
{ // FIXME: We don't support "one character" as the spec says http://www.w3.org/TR/css3-text/#text-align0
elementVerifiers.put(element,new CSSPropertyVerifier( Arrays.asList("start","end","left","right","center","justify","match-parent"),ElementInfo.VISUALMEDIA));
@@ -1430,15 +1506,20 @@ else if("text-autospace".equalsIgnoreCase(element))
allelementVerifiers.remove(element);
}
+ else if("text-combine-upright".equalsIgnoreCase(element))
+ {
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("none","all"),ElementInfo.VISUALMEDIA,null,null));
+ allelementVerifiers.remove(element);
+ }
else if("text-decoration".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("115a103a104a116")));
+ elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("115a73a104a116")));
allelementVerifiers.remove(element);
}
else if("text-decoration-color".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("103")));
+ elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("73")));
allelementVerifiers.remove(element);
}
@@ -1462,17 +1543,20 @@ else if("text-decoration-style".equalsIgnoreCase(element))
{
elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("104")));
allelementVerifiers.remove(element);
-
+ }
+ else if("text-decoration-thickness".equalsIgnoreCase(element))
+ {
+ elementVerifiers.put(element, new CSSPropertyVerifier(Arrays.asList("from-font", "auto"), ElementInfo.VISUALMEDIA, Arrays.asList("le", "pe")));
+ allelementVerifiers.remove(element);
}
else if("text-emphasis".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("103a107")));
+ elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("73a107")));
allelementVerifiers.remove(element);
-
}
else if("text-emphasis-color".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("103")));
+ elementVerifiers.put(element,new CSSPropertyVerifier(null,ElementInfo.VISUALMEDIA,null,Arrays.asList("73")));
allelementVerifiers.remove(element);
}
@@ -1517,22 +1601,22 @@ else if("text-overflow".equalsIgnoreCase(element))
}
else if("text-shadow".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("none"),ElementInfo.VISUALMEDIA,null,Arrays.asList("79<0,65535>"),true,true));
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("none"),ElementInfo.VISUALMEDIA,null,Arrays.asList("79"),true,true));
allelementVerifiers.remove(element);
}
else if("text-transform".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier( Arrays.asList("capitalize","uppercase","lowercase","none","fullwidth","large-kana"),ElementInfo.VISUALMEDIA));
+ elementVerifiers.put(element,new CSSPropertyVerifier( Arrays.asList("capitalize","uppercase","lowercase","none","fullwidth","full-size-kana","math-auto"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
else if("text-underline-position".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier( Arrays.asList("auto","under","alphabetic","over"),ElementInfo.VISUALMEDIA));
+ elementVerifiers.put(element,new CSSPropertyVerifier( Arrays.asList("auto","under","left","right"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
else if("text-wrap".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier( Arrays.asList("normal","unrestricted","none","suppress"),ElementInfo.VISUALMEDIA));
+ elementVerifiers.put(element,new CSSPropertyVerifier( Arrays.asList("wrap","nowrap","balance"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
else if("top".equalsIgnoreCase(element))
@@ -1558,7 +1642,7 @@ else if("transform-origin".equalsIgnoreCase(element))
}
else if("unicode-bidi".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier( Arrays.asList("normal", "embed", "bidi-override"),ElementInfo.VISUALMEDIA));
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("normal", "embed", "bidi-override", "isolate", "isolate-override", "plaintext"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
else if("vertical-align".equalsIgnoreCase(element))
@@ -1586,12 +1670,9 @@ else if("white-space".equalsIgnoreCase(element))
elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("normal","pre","nowrap","pre-wrap","pre-line"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
- else if("white-space-collapsing".equalsIgnoreCase(element))
+ else if("white-space-collapse".equalsIgnoreCase(element))
{
- auxilaryVerifiers[80]=new CSSPropertyVerifier(Arrays.asList("preserve","preserve-break"),null,null,null,true);
- auxilaryVerifiers[81]=new CSSPropertyVerifier(Arrays.asList("trim-inner"),null,null,null,true);
- auxilaryVerifiers[82]=new CSSPropertyVerifier(null,null,Arrays.asList("80a81"),null,true);
- elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("collapse" ,"discard"),null,ElementInfo.VISUALMEDIA,Arrays.asList("82")));
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("preserve","preserve-break","collapse","discard","break-spaces"),null,ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
else if("widows".equalsIgnoreCase(element))
@@ -1606,7 +1687,7 @@ else if("width".equalsIgnoreCase(element))
}
else if("word-break".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("normal","break-all","hyphenate"),ElementInfo.VISUALMEDIA));
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("normal","break-all","hyphenate","keep-all"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
else if("word-spacing".equalsIgnoreCase(element))
@@ -1614,9 +1695,15 @@ else if("word-spacing".equalsIgnoreCase(element))
elementVerifiers.put(element,new CSSPropertyVerifier(null,null,ElementInfo.VISUALMEDIA,Arrays.asList("85<1,3>")));
allelementVerifiers.remove(element);
}
- else if("word-wrap".equalsIgnoreCase(element))
+ else if("word-wrap".equalsIgnoreCase(element) || "overflow-wrap".equalsIgnoreCase(element))
+ {
+ // word-wrap was a Microsoft extension that got renamed to overflow-wrap in CSS Text Module Level 3.
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("normal", "break-word", "anywhere"),ElementInfo.VISUALMEDIA));
+ allelementVerifiers.remove(element);
+ }
+ else if("writing-mode".equalsIgnoreCase(element))
{
- elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("normal", "break-word"),ElementInfo.VISUALMEDIA));
+ elementVerifiers.put(element,new CSSPropertyVerifier(Arrays.asList("horizontal-tb", "vertical-rl", "vertical-lr", "lr", "lr-tb", "rl", "tb", "tb-lr", "tb-rl"),ElementInfo.VISUALMEDIA));
allelementVerifiers.remove(element);
}
else if("z-index".equalsIgnoreCase(element))
@@ -1707,7 +1794,7 @@ private int checkImportant(ParsedWord[] words) {
}
/*
- * This function accepts an HTML element(along with class name, ID, pseudo class and attribute selector) and determines whether it is valid or not.
+ * This function accepts an HTML element(along with class name, ID, pseudo class or attribute selector or a combinator) and determines whether it is valid or not.
* Returns null on failure (invalid selector), empty string on banned (but otherwise valid) selector.
* @param elementName A selector which may include an HTML element.
* @param isIDSelector True if we only allow an ID selector, which must include an ID, may
@@ -1772,26 +1859,27 @@ else if(HTMLelement.indexOf('#')!=-1)
}
}
- if(isIDSelector && "".equals(id)) return null; // No ID
+ if(isIDSelector && id.isEmpty()) return null; // No ID
boolean elementValid =
"*".equals(HTMLelement) ||
+ "~".equals(HTMLelement) ||
(ElementInfo.isValidHTMLTag(HTMLelement.toLowerCase())) ||
- ("".equals(HTMLelement.trim()) &&
- ((!className.equals("")) || (!id.equals("")) || attSelections!=null ||
- !pseudoClass.equals("")));
+ (HTMLelement.trim().isEmpty() &&
+ ((!className.isEmpty()) || (!id.isEmpty()) || attSelections!=null ||
+ !pseudoClass.isEmpty()));
if(!elementValid) return null;
- if(!className.equals("")) {
+ if(!className.isEmpty()) {
// Note that the definition of isValidName() allows chained classes because it allows . in class names.
if(!ElementInfo.isValidName(className))
return null;
- } else if(!id.equals("")) {
+ } else if(!id.isEmpty()) {
if(!ElementInfo.isValidName(id))
return null;
}
- if(!pseudoClass.equals("")) {
+ if(!pseudoClass.isEmpty()) {
if(!ElementInfo.isValidPseudoClass(pseudoClass)) {
return null;
} else if(ElementInfo.isBannedPseudoClass(pseudoClass)) {
@@ -1800,26 +1888,22 @@ else if(HTMLelement.indexOf('#')!=-1)
}
if(attSelections!=null) {
- String[] attSelectionParts;
for(String attSelection : attSelections) {
- if(attSelection.indexOf("|=")!=-1) {
- attSelectionParts=new String[2];
- attSelectionParts[0]=attSelection.substring(0,attSelection.indexOf("|="));
- attSelectionParts[1]=attSelection.substring(attSelection.indexOf("|=")+2,
- attSelection.length());
- } else if(attSelection.indexOf("~=")!=-1) {
- attSelectionParts=new String[2];
- attSelectionParts[0]=attSelection.substring(0,attSelection.indexOf("~="));
- attSelectionParts[1]=attSelection.substring(attSelection.indexOf("~=")+2,
- attSelection.length());
- } else if(attSelection.indexOf('=') != -1){
- attSelectionParts=new String[2];
- attSelectionParts[0]=attSelection.substring(0,attSelection.indexOf('='));
- attSelectionParts[1]=attSelection.substring(attSelection.indexOf('=')+1,
- attSelection.length());
- } else {
- attSelectionParts=new String[] { attSelection };
+
+ // set the default
+ String[] attSelectionParts = new String[] { attSelection };
+
+ List operators = Arrays.asList("|=", "~=", "^=", "$=", "*=", "=");
+ for (String comparisonOperator : operators) {
+ if (attSelection.contains(comparisonOperator)) {
+ attSelectionParts = new String[2];
+ attSelectionParts[0] = attSelection
+ .substring(0, attSelection.indexOf(comparisonOperator));
+ attSelectionParts[1] = attSelection
+ .substring(attSelection.indexOf(comparisonOperator) + comparisonOperator.length());
+ break;
+ }
}
//Verifying whether each character is alphanumeric or _
@@ -1827,13 +1911,14 @@ else if(HTMLelement.indexOf('#')!=-1)
"HTMLelementVerifier length of attSelectionParts="+
attSelectionParts.length);
- if(attSelectionParts[0].length()==0)
+ if(attSelectionParts[0].isEmpty())
return null;
else {
char c=attSelectionParts[0].charAt(0);
if(!((c>='a' && c<='z') || (c>='A' && c<='Z')))
return null;
for(int i=1;i='a' && c<='z') || (c>='A' && c<='Z') || c=='_' || c=='-'))
return null;
}
@@ -1852,14 +1937,14 @@ else if(HTMLelement.indexOf('#')!=-1)
}
fBuffer.append(HTMLelement);
- if(!className.equals("")) {
+ if(!className.isEmpty()) {
fBuffer.append('.');
fBuffer.append(className);
- } else if(!id.equals("")) {
+ } else if(!id.isEmpty()) {
fBuffer.append('#');
fBuffer.append(id);
}
- if(!pseudoClass.equals("")) {
+ if(!pseudoClass.isEmpty()) {
fBuffer.append(':');
fBuffer.append(pseudoClass);
}
@@ -2164,7 +2249,7 @@ else if(parts[0] instanceof SimpleParsedWord && "@media".equals(((SimpleParsedWo
valid = false;
} else {
ArrayList medias = commaListFromIdentifiers(parts, 1);
- if(medias != null && medias.size() > 0) {
+ if(medias != null && !medias.isEmpty()) {
for(i=0;i 0) {
+ if(medias != null && !medias.isEmpty()) {
filteredTokens.append(braceSpace);
filteredTokens.append("@media ");
boolean first = true;
@@ -2360,7 +2445,7 @@ else if(parts[0] instanceof SimpleParsedWord && "@media".equals(((SimpleParsedWo
if(!isState1Present)
{
String s = buffer.toString().trim();
- if(!(s.equals("") || s.equals("/") || s.equals("<") || s.equals(" 2) {
char c = strippedOrig.charAt(0);
@@ -3587,7 +3672,7 @@ private static ParsedWord parseToken(StringBuilder origToken, StringBuilder deco
decodedToken.setLength(decodedToken.length()-(strippedOrig.length()-i-1));
strippedOrig = strippedOrig.substring(0, i+1);
- if(strippedOrig.length() == 0) return null;
+ if(strippedOrig.isEmpty()) return null;
return new ParsedAttr(origToken.toString(), decodedToken.toString(), dontLikeOrigToken);
} else return null;
@@ -3618,7 +3703,7 @@ private static ParsedWord parseToken(StringBuilder origToken, StringBuilder deco
decodedToken.setLength(decodedToken.length()-(strippedOrig.length()-i-1));
strippedOrig = strippedOrig.substring(0, i+1);
- if(strippedOrig.length() == 0) return null;
+ if(strippedOrig.isEmpty()) return null;
String[] split = FilterUtils.removeWhiteSpace(strippedOrig.split(","),false);
if(split.length == 0 || (plural && split.length > 3) || ((!plural) && split.length > 2) || (plural && split.length < 2))
@@ -3846,7 +3931,7 @@ public static boolean isValidURI(ParsedURL word, FilterCallback cb)
{
//if(debug) Logger.debug(this, "CSSPropertyVerifier isVaildURI "+cb.processURI(URI, null));
String s = cb.processURI(w, null);
- if(s == null || s.equals("")) return false;
+ if(s == null || s.isEmpty()) return false;
if(s.equals(w)) return true;
if(logDEBUG) Logger.debug(CSSTokenizerFilter.class, "New url: \""+s+"\" from \""+w+"\"");
word.setNewURL(s);
@@ -3915,7 +4000,7 @@ public boolean checkValidity(String[] media,String[] elements,ParsedWord[] words
// CSS Property has one of the explicitly defined values
return true;
}
- if (lowerCaseWord.equals("initial") || lowerCaseWord.equals("inherit") || lowerCaseWord.equals("unset")) {
+ if (lowerCaseWord.equals("initial") || lowerCaseWord.equals("inherit") || lowerCaseWord.equals("unset") || lowerCaseWord.equals("revert") || lowerCaseWord.equals("revert-layer")) {
// CSS Property is one of the Defaulting Keywords (http://www.w3.org/TR/css3-cascade/#defaulting-keywords)
return true;
}
@@ -3986,10 +4071,15 @@ public boolean checkValidity(String[] media,String[] elements,ParsedWord[] words
}
}
- if(words[0] instanceof ParsedIdentifier && isColor) {
- if(FilterUtils.isColor(((ParsedIdentifier)words[0]).original))
+ if(words[0] instanceof ParsedIdentifier) {
+ String value = ((ParsedIdentifier)words[0]).original;
+ if(isColor && FilterUtils.isColor(value)) {
return true;
-
+ }
+ if(isLength && (value.equalsIgnoreCase("min-content") || value.equalsIgnoreCase("max-content") || value.equalsIgnoreCase("fit-content"))) {
+ //TODO: support fit-content(20em)
+ return true;
+ }
}
if(isURI && words[0] instanceof ParsedURL)
@@ -4011,7 +4101,7 @@ public boolean checkValidity(String[] media,String[] elements,ParsedWord[] words
// 2) We should sanitize the selectors, not just pass them on. Which in turn may
// cause them to take up more than one word!
String result = HTMLelementVerifier(words[0].original, true);
- if (!(result == null || result.equals(""))) {
+ if (!(result == null || result.isEmpty())) {
return true;
}
}
@@ -4084,7 +4174,7 @@ public boolean checkValidity(String[] media,String[] elements,ParsedWord[] words
public boolean recursiveParserExpressionVerifier(String expression,ParsedWord[] words, FilterCallback cb)
{
if(logDEBUG) Logger.debug(this, "1recursiveParserExpressionVerifier called: with "+expression+" "+toString(words));
- if((expression==null || ("".equals(expression.trim()))))
+ if((expression==null || (expression.trim().isEmpty())))
{
if(words==null || words.length == 0)
return true;
@@ -4115,7 +4205,7 @@ public boolean recursiveParserExpressionVerifier(String expression,ParsedWord[]
if(endIndex!=expression.length())
secondPart=expression.substring(endIndex+1,expression.length());
int j = 1;
- if((secondPart.equals(""))) {
+ if((secondPart.isEmpty())) {
// This is an optimisation: If no second part, there cannot be any words assigned to the second part, so the first part must match everything.
// It is equivalent to running the loop, because each time the second part will fail, because it is trying to match "" to a nonzero number of words.
// This happens every time we have "1a2a3" with nothing after it, so it is tested by the unit tests already.
@@ -4219,9 +4309,9 @@ else if(expression.charAt(i)=='<')
}
String firstPart=expression.substring(0,i);
String secondPart=expression.substring(firstIndex,expression.length());
- if(secondPart.length() > 0 && secondPart.charAt(0) == ' ') {
+ if(!secondPart.isEmpty() && secondPart.charAt(0) == ' ') {
secondPart = secondPart.substring(1);
- } else if(secondPart.length() > 0) {
+ } else if(!secondPart.isEmpty()) {
throw new IllegalStateException("Don't know what to do with char after <>[]: "+secondPart.charAt(0));
}
if(logDEBUG) Logger.debug(this, "9in < firstPart="+firstPart+" secondPart="+secondPart+" tokensCanBeGivenLowerLimit="+tokensCanBeGivenLowerLimit+" tokensCanBeGivenUpperLimit="+tokensCanBeGivenUpperLimit);
@@ -4267,7 +4357,7 @@ public boolean doubleAmpersandVerifier(String expression, ParsedWord[] words, Fi
String firstPart = "";
int lastB = -1;
// Check for invalid patterns.
- assert(expression.length() != 0);
+ assert(!expression.isEmpty());
assert(expression.charAt(expression.length()-1) != 'b');
assert(expression.charAt(0) != 'b');
@@ -4275,8 +4365,8 @@ public boolean doubleAmpersandVerifier(String expression, ParsedWord[] words, Fi
List propertyVerifierList = new ArrayList();
for (int i = 0; i <= expression.length(); i++) {
if(i == expression.length() || expression.charAt(i)=='b') {
- if(!firstPart.equals("")) {
- if(ignoredParts.length() == 0) {
+ if(!firstPart.isEmpty()) {
+ if(ignoredParts.isEmpty()) {
ignoredParts = firstPart;
} else {
ignoredParts = ignoredParts+"b"+firstPart;
@@ -4297,7 +4387,7 @@ public boolean doubleAmpersandVerifier(String expression, ParsedWord[] words, Fi
// list we do not want that potential false positive and so here we are
// forcing the verifier to take at least one word.
int maxLoops = words.length;
- while (maxLoops-- > 0 && propertyVerifierList.size() != 0) {
+ while (maxLoops-- > 0 && !propertyVerifierList.isEmpty()) {
for(int i = words.length; i > 0; i--) {
ParsedWord[] tokensToVerify = Arrays.copyOf(words, i);
boolean tokenConsumed = false;
@@ -4460,15 +4550,15 @@ public boolean recursiveDoubleBarVerifier(String expression,ParsedWord[] words,F
String secondPart = "";
int lastA = -1;
// Check for invalid patterns.
- assert(expression.length() != 0);
+ assert(!expression.isEmpty());
assert(expression.charAt(expression.length()-1) != 'a');
assert(expression.charAt(0) != 'a');
for(int i=0;i<=expression.length();i++)
{
if(i == expression.length() || expression.charAt(i)=='a')
{
- if(!firstPart.equals("")) {
- if(ignoredParts.length() == 0)
+ if(!firstPart.isEmpty()) {
+ if(ignoredParts.isEmpty())
ignoredParts = firstPart;
else
ignoredParts = ignoredParts+"a"+firstPart;
@@ -4501,9 +4591,9 @@ public boolean recursiveDoubleBarVerifier(String expression,ParsedWord[] words,F
}
// Against the rest of the pattern: the part that we've tried and failed plus the part that we haven't tried yet.
// NOT against the verifier we were just considering, because the double-bar operator expects no more than one match from each component of the pattern.
- String pattern = ignoredParts+((("".equals(ignoredParts))||("".equals(secondPart)))?"":"a")+secondPart;
+ String pattern = ignoredParts+(((ignoredParts.isEmpty())||(secondPart.isEmpty()))?"":"a")+secondPart;
if(logDEBUG) Logger.debug(this, "14a "+toString(getSubArray(words, 0, j+1))+" can be consumed by "+index+ " passing on expression="+pattern+ " value="+toString(valueToPass));
- if(pattern.equals("")) return false;
+ if(pattern.isEmpty()) return false;
result=recursiveDoubleBarVerifier(pattern,valueToPass, cb);
if(result)
{
@@ -4623,7 +4713,7 @@ public boolean checkValidity(String[] media,String[] elements,ParsedWord[] value
if(fontSize.checkValidity(word, cb)) continue;
if(word instanceof SimpleParsedWord) {
String orig = ((SimpleParsedWord)word).original;
- if(orig.indexOf("/")!=-1)
+ if(orig.contains("/"))
{
int slashIndex=orig.indexOf("/");
String firstPart=orig.substring(0,slashIndex);
diff --git a/src/freenet/client/filter/ContentFilter.java b/src/freenet/client/filter/ContentFilter.java
index 4d54298677d..3ae493ca552 100644
--- a/src/freenet/client/filter/ContentFilter.java
+++ b/src/freenet/client/filter/ContentFilter.java
@@ -81,6 +81,12 @@ true, false, new PNGFilter(true, true, true), false, false, false, false, true,
true, false, new BMPFilter(), false, false, false, false, true, false,
l10n("imageBMPReadAdvice"),
false, null, null, false));
+
+ // WEBP - has a filter
+ register(new FilterMIMEType("image/webp", "webp", new String[] { "image/webp" }, new String[0],
+ true, false, new WebPFilter(), false, false, false, false, true, false,
+ l10n("imageWebPReadAdvice"),
+ false, null, null, false));
/* Ogg - has a filter
* Xiph's container format. Contains one or more logical bitstreams.
@@ -92,7 +98,7 @@ true, false, new BMPFilter(), false, false, false, false, true, false,
true, false, new OggFilter(), true, true, false, true, false, false,
l10n("containerOggReadAdvice"),false, null, null, false));
- /* FLAC - Needs filter
+ /* FLAC - has a filter
* Lossless audio format. This data is sometimes encapsulated inside
* of ogg containers. It is, however, not currently supported, and
* is very dangerous, as it may specify URLs from which album art
@@ -335,7 +341,7 @@ public static FilterStatus filter(InputStream input, OutputStream output, String
else {
// Run the read filter if there is one.
if(handler.readFilter != null) {
- if(handler.takesACharset && ((charset == null) || (charset.length() == 0))) {
+ if(handler.takesACharset && ((charset == null) || (charset.isEmpty()))) {
int bufferSize = handler.charsetExtractor.getCharsetBufferSize();
input.mark(bufferSize);
byte[] charsetBuffer = new byte[bufferSize];
@@ -448,7 +454,7 @@ public static String detectCharset(byte[] input, int length, FilterMIMEType hand
}
// If no BOM, use the charset from the referring document.
- if(handler.useMaybeCharset && maybeCharset != null && (maybeCharset.length() != 0))
+ if(handler.useMaybeCharset && maybeCharset != null && (!maybeCharset.isEmpty()))
return maybeCharset;
if(charset != null)
diff --git a/src/freenet/client/filter/ElementInfo.java b/src/freenet/client/filter/ElementInfo.java
index 1737accfde9..e31cf259e7f 100644
--- a/src/freenet/client/filter/ElementInfo.java
+++ b/src/freenet/client/filter/ElementInfo.java
@@ -4,6 +4,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
+import java.util.regex.Pattern;
public class ElementInfo {
@@ -53,42 +54,6 @@ public class ElementInfo {
"button"
)));
- // FIXME add some more languages.
- public static final Set LANGUAGES =
- Collections.unmodifiableSet(new HashSet(Arrays.asList(
- "az",
- "be",
- "bg",
- "cs",
- "de",
- "el",
- "en",
- "es",
- "fi",
- "fr",
- "id",
- "it",
- "ja",
- "ka",
- "kk",
- "ky",
- "lv",
- "mo",
- "nl",
- "no",
- "pl",
- "pt",
- "ro",
- "ru",
- "sv",
- "tl",
- "tr",
- "tt",
- "uk",
- "zh-hans",
- "zh-hant"
- )));
-
public static final Set MEDIA =
Collections.unmodifiableSet(new HashSet(Arrays.asList(
"all",
@@ -182,13 +147,22 @@ public class ElementInfo {
"new york6"
)));
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/font-family
public static final Set GENERIC_FONT_KEYWORDS =
Collections.unmodifiableSet(new HashSet(Arrays.asList(
"serif",
"sans-serif",
"cursive",
"fantasy",
- "monospace"
+ "monospace",
+ "system-ui",
+ "ui-serif",
+ "ui-sans-serif",
+ "ui-monospace",
+ "ui-rounded",
+ "emoji",
+ "math",
+ "fangsong"
)));
public static final Set GENERIC_VOICE_KEYWORDS =
@@ -206,18 +180,37 @@ public class ElementInfo {
"nth-last-child",
"nth-of-type",
"nth-last-of-type",
- "link",
- "visited",
+ "link", // inverse of visited (see BANNED_PSEUDOCLASS below)
+ "visited", // privacy risk (see BANNED_PSEUDOCLASS below)
"hover",
"active",
+ "checked", // forms
"focus",
"focus-within",
- "lang",
"first-line",
"first-letter",
"before",
"after",
- "target"
+ "target",
+ "any-link",
+ "default", // forms
+ "defined", // Javascript only (BANNED_PSEUDOCLASS)
+ "disabled", // forms
+ "empty",
+ "enabled", // forms
+ "focus-visible",
+ "indeterminate", // forms
+ "in-range", // forms
+ "invalid", // forms
+ "only-child",
+ "only-of-type",
+ "optional", // forms
+ "out-of-range", // forms
+ "placeholder-shown", // forms
+ "read-only", // forms
+ "read-write", // forms
+ "required", // forms
+ "root"
)));
public static final Set BANNED_PSEUDOCLASS =
@@ -248,7 +241,10 @@ public class ElementInfo {
// is considered too much of a danger, so we scrub that pseudoclass.
//
// [1] http://lcamtuf.coredump.cx/css_calc/
- "visited"
+ "link",
+ "visited",
+ // Javascript only
+ "defined"
)));
public static boolean isSpecificFontFamily(String font) {
@@ -322,7 +318,7 @@ public static boolean isValidHTMLTag(String tag)
*/
public static boolean isValidName(String name)
{
- if(name.length()==0)
+ if(name.isEmpty())
{
return false;
}
@@ -350,7 +346,7 @@ public static boolean isValidName(String name)
public static boolean isValidIdentifier(String name)
{
- if(name.length()==0)
+ if(name.isEmpty())
{
return false;
}
@@ -431,50 +427,64 @@ public static boolean isBannedPseudoClass(String cname)
// Pseudo-classes can be chained, at least dynamic ones can, see CSS2.1 section 5.11.3
String[] split = cname.split(":");
for(String s : split)
- if(isBannedPseudoClass(s)) return true;
+ if(isBannedPseudoClass2(s)) return true;
return false;
+ } else {
+ return isBannedPseudoClass2(cname);
}
- cname=cname.toLowerCase();
- return BANNED_PSEUDOCLASS.contains(cname);
}
+ private static boolean isBannedPseudoClass2(String cname)
+ {
+ return BANNED_PSEUDOCLASS.contains(cname.toLowerCase());
+ }
+
public static boolean isValidPseudoClass(String cname)
{
if(cname.indexOf(':') != -1) {
// Pseudo-classes can be chained, at least dynamic ones can, see CSS2.1 section 5.11.3
String[] split = cname.split(":");
for(String s : split)
- if(!isValidPseudoClass(s)) return false;
+ if(!isValidPseudoClass2(s)) return false;
return true;
+ } else {
+ return isValidPseudoClass2(cname);
}
+ }
+
+ private static boolean isValidPseudoClass2(String cname)
+ {
cname=cname.toLowerCase();
if(PSEUDOCLASS.contains(cname))
return true;
-
-
- else if(cname.indexOf("lang")!=-1 && LANGUAGES.contains(getPseudoClassArg(cname, "lang")))
+ else if(cname.startsWith("lang") && Pattern.matches("[\\w\\-*]{1,30}", getPseudoClassArg(cname, "lang")))
{
- // FIXME accept unknown languages as long as they are [a-z-]
+ // More than 8000 valid BCP-47 language codes. Just let through all of them.
return true;
}
-
- else if(cname.indexOf("nth-child")!=-1 && FilterUtils.isNth(getPseudoClassArg(cname, "nth-child")))
+ else if(cname.startsWith("nth-child") && FilterUtils.isNth(getPseudoClassArg(cname, "nth-child")))
return true;
- else if(cname.indexOf("nth-last-child")!=-1 && FilterUtils.isNth(getPseudoClassArg(cname, "nth-last-child")))
+ else if(cname.startsWith("nth-last-child") && FilterUtils.isNth(getPseudoClassArg(cname, "nth-last-child")))
return true;
- else if(cname.indexOf("nth-of-type")!=-1 && FilterUtils.isNth(getPseudoClassArg(cname, "nth-of-type")))
+ else if(cname.startsWith("nth-of-type") && FilterUtils.isNth(getPseudoClassArg(cname, "nth-of-type")))
return true;
- else if(cname.indexOf("nth-last-of-type")!=-1 && FilterUtils.isNth(getPseudoClassArg(cname, "nth-last-of-type")))
+ else if(cname.startsWith("nth-last-of-type") && FilterUtils.isNth(getPseudoClassArg(cname, "nth-last-of-type")))
return true;
-
+ else if(cname.startsWith("dir")) {
+ String arg = getPseudoClassArg(cname, "dir");
+ return arg.equalsIgnoreCase("ltr") || arg.equalsIgnoreCase("rtl");
+ }
return false;
- }
+ }
+
public static String getPseudoClassArg(String cname, String cname_sans_arg) {
String arg="";
int cnameIndex=cname.indexOf(cname_sans_arg);
int firstIndex=cname.indexOf('(');
int secondIndex=cname.lastIndexOf(')');
- if(cname.substring(cnameIndex+cname_sans_arg.length(),firstIndex).trim().equals("") && cname.substring(0,cnameIndex).trim().equals("") && cname.substring(secondIndex+1,cname.length()).trim().equals(""))
+ if(cnameIndex == -1 || firstIndex == -1 || secondIndex == -1)
+ return "";
+ if(cname.substring(cnameIndex + cname_sans_arg.length(), firstIndex).trim().isEmpty() && cname.substring(0, cnameIndex).trim().isEmpty() && cname.substring(secondIndex + 1, cname.length()).trim().isEmpty())
{
arg=CSSTokenizerFilter.removeOuterQuotes(cname.substring(firstIndex+1,secondIndex).trim());
}
diff --git a/src/freenet/client/filter/FilterUtils.java b/src/freenet/client/filter/FilterUtils.java
index c38a6d2f892..9140bce988c 100644
--- a/src/freenet/client/filter/FilterUtils.java
+++ b/src/freenet/client/filter/FilterUtils.java
@@ -4,6 +4,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.regex.Pattern;
public class FilterUtils {
private static volatile boolean logDEBUG;
@@ -103,7 +104,7 @@ public static boolean isLength(String value,boolean isSVG) //SVG lengths allow %
{
String lengthValue=null;
value=value.trim();
- if (value.length() == 0) {
+ if (value.isEmpty()) {
return false;
}
if (isSVG) {
@@ -150,14 +151,14 @@ public static boolean isAngle(String value)
{
boolean isValid=true;
int index=-1;
- if(value.indexOf("deg")>-1)
+ if(value.contains("deg"))
{
index=value.indexOf("deg");
String secondpart=value.substring(index,value.length()).trim();
if(!("deg".equals(secondpart)))
isValid=false;
}
- else if(value.indexOf("grad")>-1)
+ else if(value.contains("grad"))
{
index=value.indexOf("grad");
String secondpart=value.substring(index,value.length()).trim();
@@ -165,7 +166,7 @@ else if(value.indexOf("grad")>-1)
if(!("grad".equals(secondpart)))
isValid=false;
}
- else if(value.indexOf("rad")>-1)
+ else if(value.contains("rad"))
{
index=value.indexOf("rad");
String secondpart=value.substring(index,value.length()).trim();
@@ -289,6 +290,7 @@ else if(value.indexOf("rad")>-1)
SVGcolorKeywords.add("whitesmoke");
SVGcolorKeywords.add("yellow");
SVGcolorKeywords.add("yellowgreen");
+ SVGcolorKeywords.add("rebeccapurple"); // CSS Colors Level 4: #663399
}
private final static HashSet CSScolorKeywords=new HashSet();
static
@@ -315,34 +317,34 @@ else if(value.indexOf("rad")>-1)
}
private final static HashSet CSSsystemColorKeywords=new HashSet();
static {
- CSScolorKeywords.add("ActiveBorder");
- CSScolorKeywords.add("ActiveCaption");
- CSScolorKeywords.add("AppWorkspace");
- CSScolorKeywords.add("Background");
- CSScolorKeywords.add("ButtonFace");
- CSScolorKeywords.add("ButtonHighlight");
- CSScolorKeywords.add("ButtonShadow");
- CSScolorKeywords.add("ButtonText");
- CSScolorKeywords.add("CaptionText");
- CSScolorKeywords.add("GrayText");
- CSScolorKeywords.add("Highlight");
- CSScolorKeywords.add("HighlightText");
- CSScolorKeywords.add("InactiveBorder");
- CSScolorKeywords.add("InactiveCaption");
- CSScolorKeywords.add("InactiveCaptionText");
- CSScolorKeywords.add("InfoBackground");
- CSScolorKeywords.add("InfoText");
- CSScolorKeywords.add("Menu");
- CSScolorKeywords.add("MenuText");
- CSScolorKeywords.add("Scrollbar");
- CSScolorKeywords.add("ThreeDDarkShadow");
- CSScolorKeywords.add("ThreeDFace");
- CSScolorKeywords.add("ThreeDHighlight");
- CSScolorKeywords.add("ThreeDLightShadow");
- CSScolorKeywords.add("ThreeDShadow");
- CSScolorKeywords.add("Window");
- CSScolorKeywords.add("WindowFrame");
- CSScolorKeywords.add("WindowText");
+ CSScolorKeywords.add("activeborder");
+ CSScolorKeywords.add("activecaption");
+ CSScolorKeywords.add("appworkspace");
+ CSScolorKeywords.add("background");
+ CSScolorKeywords.add("buttonface");
+ CSScolorKeywords.add("buttonhighlight");
+ CSScolorKeywords.add("buttonshadow");
+ CSScolorKeywords.add("buttontext");
+ CSScolorKeywords.add("captiontext");
+ CSScolorKeywords.add("graytext");
+ CSScolorKeywords.add("highlight");
+ CSScolorKeywords.add("highlighttext");
+ CSScolorKeywords.add("inactiveborder");
+ CSScolorKeywords.add("inactivecaption");
+ CSScolorKeywords.add("inactivecaptiontext");
+ CSScolorKeywords.add("infobackground");
+ CSScolorKeywords.add("infotext");
+ CSScolorKeywords.add("menu");
+ CSScolorKeywords.add("menutext");
+ CSScolorKeywords.add("scrollbar");
+ CSScolorKeywords.add("threeddarkshadow");
+ CSScolorKeywords.add("threedface");
+ CSScolorKeywords.add("threedhighlight");
+ CSScolorKeywords.add("threedlightshadow");
+ CSScolorKeywords.add("threedshadow");
+ CSScolorKeywords.add("window");
+ CSScolorKeywords.add("windowframe");
+ CSScolorKeywords.add("windowtext");
}
public static boolean isValidCSSShape(String value)
{
@@ -370,70 +372,57 @@ public static boolean isValidCSSShape(String value)
public static boolean isMedia(String media) {
return cssMedia.contains(media);
}
+
+ public static final Pattern hexColorPattern = Pattern.compile("#(?>[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3,4})", Pattern.CASE_INSENSITIVE);
+
public static boolean isColor(String value)
{
- value=value.trim();
+ value=value.trim().toLowerCase();
if(CSScolorKeywords.contains(value) || CSSsystemColorKeywords.contains(value) || SVGcolorKeywords.contains(value))
return true;
if(value.indexOf('#')==0)
{
-
- if(value.length()==4)
+ return hexColorPattern.matcher(value).matches();
+ }
+ if((value.startsWith("rgb(") || value.startsWith("rgba(")) && value.indexOf(')')==value.length()-1)
+ {
+ // rgba is an alias to rgb
+ if(value.contains(","))
{
- try{
- Integer.valueOf(value.substring(1,2),16).intValue();
- Integer.valueOf(value.substring(2,3),16).intValue();
- Integer.valueOf(value.substring(3,4),16).intValue();
- return true;
- }
- catch(Exception e)
+ // Legacy format rgba(r,g,b,a)
+ String[] colorParts=value.substring(value.indexOf("(")+1,value.length()-1).split(",");
+ if(colorParts.length!=3&&colorParts.length!=4)
+ return false;
+ for(int i=0; i<3; i++)
{
+ if(!(isPercentage(colorParts[i].trim()) || isInteger(colorParts[i].trim())))
+ return false;
}
-
- }
- else if(value.length()==7)
- {
-
- try{
- Integer.valueOf(value.substring(1,3),16).intValue();
- Integer.valueOf(value.substring(3,5),16).intValue();
- Integer.valueOf(value.substring(5,7),16).intValue();
+ if(colorParts.length<=3 || isNumber(colorParts[3]))
return true;
+ }else{
+ if(value.contains("/")){
+ // Modern format rgba(r g b / a)
+ String alphaPart=value.substring(value.indexOf("/")+1,value.length()-1).trim();
+ if(!alphaPart.isEmpty() && !isPercentage(alphaPart) && !isNumber(alphaPart) && !alphaPart.equalsIgnoreCase("none"))
+ return false;
+ value=value.substring(0,value.indexOf("/"))+")"; // Strip alpha value, proceed to the following tests
+ }
+ // Modern format rgba(r g b)
+ String[] colorParts=value.substring(value.indexOf("(")+1,value.length()-1).split(" ");
+ if(colorParts.length!=3) {
+ return false;
}
- catch(Exception e)
+ for(int i=0; i<3; i++)
{
+ String trimmed = colorParts[i].trim();
+ if(!(trimmed.equalsIgnoreCase("none") || isPercentage(trimmed) || (isInteger(trimmed) && isIntegerInRange(trimmed, 0, 255))))
+ return false;
}
- }
- }
- if(value.indexOf("rgb(")==0 && value.indexOf(')')==value.length()-1)
- {
- String[] colorParts=value.substring(4,value.length()-1).split(",");
- if(colorParts.length!=3)
- return false;
- boolean isValidColorParts=true;
- for(int i=0; i-1 && value.length()>2)
+ if(value.contains("ms") && value.length()>2)
intValue=value.substring(0,value.length()-2);
else if(value.indexOf('s')>-1 && value.length()>1)
intValue=value.substring(0,value.length()-1);
@@ -648,7 +637,7 @@ public static String[] removeWhiteSpace(String[] values, boolean stripQuotes)
value = value.trim();
if(stripQuotes)
value = CSSTokenizerFilter.removeOuterQuotes(value).trim();
- if(value!=null && !("".equals(value.trim())))
+ if(value!=null && !(value.trim().isEmpty()))
arrayToReturn.add(value);
}
return arrayToReturn.toArray(new String[0]);
diff --git a/src/freenet/client/filter/FlacFilter.java b/src/freenet/client/filter/FlacFilter.java
index 774558fd5aa..fd79d24629f 100644
--- a/src/freenet/client/filter/FlacFilter.java
+++ b/src/freenet/client/filter/FlacFilter.java
@@ -19,7 +19,7 @@
*/
public class FlacFilter implements ContentDataFilter {
static final byte[] magicNumber = new byte[] {0x66, 0x4C, 0x61, 0x43};
- enum State {UNINITIALIZED, STREAMINFO_FOUND, METADATA_FOUND, STREAM_FINISHED};
+ enum State {UNINITIALIZED, STREAMINFO_FOUND, METADATA_FOUND, STREAM_FINISHED}
public void readFilter(
InputStream input, OutputStream output,
@@ -56,8 +56,8 @@ public void readFilter(
boolean firstHalfOfSyncHeaderFound = false;
ArrayList buffer = new ArrayList();
int data = 0;
- buffer.add(Byte.valueOf((byte) ((frameHeader & 0xFF00) >>> 8)));
- buffer.add(Byte.valueOf((byte) (frameHeader & 0x00FF)));
+ buffer.add((byte) ((frameHeader & 0xFF00) >>> 8));
+ buffer.add((byte) (frameHeader & 0x00FF));
boolean running = true;
while(running) {
try {
@@ -90,10 +90,10 @@ public void readFilter(
packet = new FlacFrame(payload);
} else {
firstHalfOfSyncHeaderFound = false;
- buffer.add(Byte.valueOf((byte) 0xFF));
+ buffer.add((byte) 0xFF);
}
}
- buffer.add(Byte.valueOf((byte) (data & 0xFF)));
+ buffer.add((byte) (data & 0xFF));
}
}
if(currentState == State.UNINITIALIZED && packet instanceof FlacMetadataBlock && ((FlacMetadataBlock) packet).isLastMetadataBlock()) {
diff --git a/src/freenet/client/filter/FlacPacket.java b/src/freenet/client/filter/FlacPacket.java
index 9f55c6f2e07..1d97a8e7bba 100644
--- a/src/freenet/client/filter/FlacPacket.java
+++ b/src/freenet/client/filter/FlacPacket.java
@@ -11,7 +11,7 @@ public abstract class FlacPacket extends CodecPacket {
class FlacMetadataBlock extends FlacPacket {
enum BlockType {STREAMINFO, PADDING, APPLICATION, SEEKTABLE, VORBIS_COMMENT,
- CUESHEET, PICTURE, UNKNOWN, INVALID};
+ CUESHEET, PICTURE, UNKNOWN, INVALID}
private FlacMetadataBlockHeader header = new FlacMetadataBlockHeader();
FlacMetadataBlock(int header, byte[] payload) {
diff --git a/src/freenet/client/filter/FlacPacketFilter.java b/src/freenet/client/filter/FlacPacketFilter.java
index 01f29d55ee6..599402f63a1 100644
--- a/src/freenet/client/filter/FlacPacketFilter.java
+++ b/src/freenet/client/filter/FlacPacketFilter.java
@@ -14,7 +14,7 @@
public class FlacPacketFilter implements CodecPacketFilter {
boolean streamValid = true;
- enum State {UNINITIALIZED, STREAMINFO_FOUND, METADATA_FOUND};
+ enum State {UNINITIALIZED, STREAMINFO_FOUND, METADATA_FOUND}
State currentState = State.UNINITIALIZED;
int minimumBlockSize;
diff --git a/src/freenet/client/filter/GenericReadFilterCallback.java b/src/freenet/client/filter/GenericReadFilterCallback.java
index 3d5e042b740..c2d015aec02 100644
--- a/src/freenet/client/filter/GenericReadFilterCallback.java
+++ b/src/freenet/client/filter/GenericReadFilterCallback.java
@@ -458,7 +458,7 @@ public String processForm(String method, String action) throws CommentException
String path = uri.getPath();
if(path.startsWith(PLUGINS_PREFIX)) {
String after = path.substring(PLUGINS_PREFIX.length());
- if(after.indexOf("../") > -1)
+ if(after.contains("../"))
throw new CommentException(l10n("invalidFormURIAttemptToEscape"));
if(after.matches("[A-Za-z0-9\\.]+"))
return uri.toASCIIString();
diff --git a/src/freenet/client/filter/HTMLFilter.java b/src/freenet/client/filter/HTMLFilter.java
index 1372b571cd2..83dd3d7cfb6 100644
--- a/src/freenet/client/filter/HTMLFilter.java
+++ b/src/freenet/client/filter/HTMLFilter.java
@@ -170,7 +170,7 @@ public void pushElementInStack(String element) {
}
public String popElementFromStack() {
- if(openElements.size()>0)
+ if(!openElements.isEmpty())
return openElements.pop();
else
return null;
@@ -218,31 +218,14 @@ void run() throws IOException, DataFilterException {
// If detecting charset, and found it, stop afterwards.
if(onlyDetectingCharset && detectedCharset != null)
return;
- int x;
-
- try {
- x = r.read();
- }
- /**
- * libgcj up to at least 4.2.2 has a bug: InputStreamReader.refill() throws this exception when BufferedInputReader.refill() returns false for EOF. See:
- * line 299 at InputStreamReader.java (in refill()): http://www.koders.com/java/fidD8F7E2EB1E4C22DA90EBE0130306AE30F876AB00.aspx?s=refill#L279
- * line 355 at BufferedInputStream.java (in refill()): http://www.koders.com/java/fid1949641524FAC0083432D79793F554CD85F46759.aspx?s=refill#L355
- * TODO: remove this when the gcj bug is fixed and the affected gcj versions are outdated.
- */
- catch(java.io.CharConversionException cce) {
- if(freenet.node.Node.checkForGCJCharConversionBug()) /* only ignore the exception on affected libgcj */
- x = -1;
- else
- throw cce;
- }
-
+ int x = r.read();
if (x == -1) {
switch (mode) {
case INTEXT :
if(textAllowed) {
saveText(b, currentTag, w, this);
} else {
- if(!b.toString().trim().equals(""))
+ if(!b.toString().trim().isEmpty())
throwFilterException(l10n("textBeforeHTML"));
}
break;
@@ -294,7 +277,7 @@ void run() throws IOException, DataFilterException {
if(textAllowed) {
saveText(b, currentTag, w, this);
} else {
- if(!b.toString().trim().equals(""))
+ if(!b.toString().trim().isEmpty())
throwFilterException(l10n("textBeforeHTML"));
}
b.setLength(0);
@@ -316,7 +299,7 @@ void run() throws IOException, DataFilterException {
if(textAllowed) {
saveText(b, currentTag, w, this);
} else {
- if(!b.toString().trim().equals(""))
+ if(!b.toString().trim().isEmpty())
throwFilterException(l10n("textBeforeHTML"));
}
@@ -454,7 +437,7 @@ void run() throws IOException, DataFilterException {
if(textAllowed) {
saveText(b, currentTag, w, this);
} else {
- if(!b.toString().trim().equals(""))
+ if(!b.toString().trim().isEmpty())
throwFilterException(l10n("textBeforeHTML"));
}
balt.setLength(0);
@@ -480,7 +463,7 @@ void run() throws IOException, DataFilterException {
//Writing the remaining tags for XHTML if any
if(getisXHTML())
{
- while(openElements.size()>0)
+ while(!openElements.isEmpty())
w.write(""+openElements.pop()+">");
}
w.flush();
@@ -662,7 +645,7 @@ String processTag(List splitTag, Writer w, HTMLParseContext pc)
if (pc.writeStyleScriptWithTag) {
pc.writeStyleScriptWithTag = false;
String style = pc.currentStyleScriptChunk;
- if ((style == null) || (style.length() == 0))
+ if ((style == null) || style.isEmpty())
pc.writeAfterTag.append("");
else
w.write(style);
@@ -793,7 +776,7 @@ public ParsedTag(List v) {
if (((len - 1 != 0) || (s.length() > 1)) && s.endsWith("/")) {
s = s.substring(0, s.length() - 1);
v.set(len - 1, s);
- if (s.length() == 0)
+ if (s.isEmpty())
len--;
endSlash = true;
// Don't need to set it back because everything is an I-value
@@ -953,47 +936,57 @@ private static Map getAllowedTagVerifiers()
emptyStringArray));
String[] group2 =
{
- "span",
- "address",
- "em",
- "strong",
- "dfn",
- "code",
- "samp",
- "kbd",
- "var",
- "cite",
"abbr",
"acronym",
- "sub",
- "sup",
- "dt",
- "dd",
- "tt",
- "i",
+ "address",
+ "article",
+ "aside",
"b",
+ "bdi",
+ "bdo",
"big",
- "small",
- "strike",
- "s",
- "u",
- "noframes",
- "fieldset",
-// Delete . So we can at least see the non-scripting code.
-// "noscript",
- "xmp",
- "listing",
- "plaintext",
"center",
- "bdo",
- "aside",
+ "cite",
+ "code",
+ "dd",
+ "details",
+ "dfn",
+ "dt",
+ "em",
+ "fieldset",
+ "figcaption",
+ "figure",
+ "footer",
"header",
+ "hgroup",
+ "i",
+ "kbd",
+ "listing",
+ "main",
+ "mark",
"nav",
- "footer",
- "article",
+ "noframes",
+ // Delete . So we can at least see the non-scripting code.
+ //"noscript",
+ "plaintext",
+ "rp",
+ "rt",
+ "ruby",
+ "s",
+ "samp",
"section",
- "hgroup",
- "wbr"};
+ "small",
+ "span",
+ "strike",
+ "strong",
+ "sub",
+ "summary",
+ "sup",
+ "tt",
+ "u",
+ "var",
+ "wbr",
+ "xmp"};
for (String x: group2)
allowedTagsVerifiers.put(
x,
@@ -1070,7 +1063,7 @@ private static Map getAllowedTagVerifiers()
"ol",
new CoreTagVerifier(
"ol",
- new String[] { "type", "compact", "start" },
+ new String[] { "type", "compact", "start", "reversed" },
emptyStringArray,
emptyStringArray,
emptyStringArray,
@@ -2177,7 +2170,7 @@ ParsedTag sanitize(ParsedTag t, HTMLParseContext pc) throws DataFilterException
}
} else if (idx > -1) {
String x = s.substring(0, idx);
- if (x.length() == 0)
+ if (x.isEmpty())
x = prevX;
x = x.toLowerCase();
String y;
@@ -2289,7 +2282,7 @@ Map sanitizeHash(Map h,
// lang, xml:lang and dir can go on anything
// lang or xml:lang = language [ "-" country [ "-" variant ] ]
// The variant can be just about anything; no way to test (avian)
- if (x.equals("xml:lang") ||x.equals("lang") || (x.equals("dir") && (o instanceof String) && (((String)o).equalsIgnoreCase("ltr") || ((String)o).equalsIgnoreCase("rtl")))) {
+ if (x.equals("xml:lang") ||x.equals("lang") || (x.equals("dir") && (o instanceof String) && (((String)o).equalsIgnoreCase("ltr") || ((String)o).equalsIgnoreCase("rtl") || ((String)o).equalsIgnoreCase("auto")))) {
if(logDEBUG) Logger.debug(this, "HTML Filter is putting attribute: "+x+" = "+o);
hn.put(x, o);
}
@@ -2645,8 +2638,9 @@ Map sanitizeHash(Map h,
if (type != null) {
String[] typesplit = splitType(type);
type = typesplit[0];
- if ((typesplit[1] != null) && (typesplit[1].length() > 0))
+ if ((typesplit[1] != null) && !typesplit[1].isEmpty()) {
charset = typesplit[1];
+ }
if(logDEBUG)
Logger.debug(
this,
@@ -2742,9 +2736,9 @@ Map sanitizeHash(Map h,
// Allow no rel or rev, even on , as per HTML spec.
- if(parsedRel.length() != 0)
+ if(!parsedRel.isEmpty())
hn.put("rel", parsedRel);
- if(parsedRev.length() != 0)
+ if(!parsedRev.isEmpty())
hn.put("rev", parsedRev);
if(rel != null) {
@@ -3004,6 +2998,9 @@ Map sanitizeHash(Map h,
} else if (name.equalsIgnoreCase("Description")) {
hn.put("name", name);
hn.put("content", content);
+ } else if (name.equalsIgnoreCase("Viewport")) {
+ hn.put("name", name);
+ hn.put("content", content);
}
} else if ((http_equiv != null) && (name == null)) {
if (http_equiv.equalsIgnoreCase("Expires")) {
@@ -3064,7 +3061,7 @@ Map sanitizeHash(Map h,
throwFilterException(l10n("invalidMetaType"));
} else if (
http_equiv.equalsIgnoreCase("Content-Language")) {
- if(content.matches("((?>[a-zA-Z0-9]*)(?>-[A-Za-z0-9]*)*(?>,\\s*)?)*") && (!content.trim().equals(""))) {
+ if(content.matches("((?>[a-zA-Z0-9]*)(?>-[A-Za-z0-9]*)*(?>,\\s*)?)*") && !content.trim().isEmpty()) {
hn.put("http-equiv", "Content-Language");
hn.put("content", content);
}
@@ -3337,7 +3334,7 @@ static String sanitizeStyle(String style, FilterCallback cb, HTMLParseContext hp
throw e;
}
String s = w.toString();
- if ((s == null) || (s.length() == 0))
+ if ((s == null) || s.isEmpty())
return null;
// Core.logger.log(SaferFilter.class, "Style now: " + s, LogLevel.DEBUG);
if(logMINOR) Logger.minor(HTMLFilter.class, "Style finally: " + s);
@@ -3452,7 +3449,7 @@ static String sanitizeURI(
if(logMINOR)
Logger.minor(HTMLFilter.class, "Sanitizing URI: "+suri+" ( override type "+overrideType +" override charset "+overrideCharset+" ) inline="+inline, new Exception("debug"));
boolean addMaybe = false;
- if((overrideCharset != null) && (overrideCharset.length() > 0))
+ if((overrideCharset != null) && !overrideCharset.isEmpty())
overrideType += "; charset="+overrideCharset;
else if(maybeCharset != null)
addMaybe = true;
diff --git a/src/freenet/client/filter/JPEGFilter.java b/src/freenet/client/filter/JPEGFilter.java
index c4041a6266d..313c161e60e 100644
--- a/src/freenet/client/filter/JPEGFilter.java
+++ b/src/freenet/client/filter/JPEGFilter.java
@@ -9,9 +9,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.Map;
import freenet.l10n.NodeL10n;
@@ -321,13 +320,9 @@ private static String l10n(String key) {
}
private void writeNullTerminatedString(ByteArrayOutputStream baos, String type) throws IOException {
- try {
- byte[] data = type.getBytes("ISO-8859-1"); // ascii, near enough
- baos.write(data);
- baos.write(0);
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support ISO-8859-1: " + e, e);
- }
+ byte[] data = type.getBytes(StandardCharsets.ISO_8859_1); // ascii, near enough
+ baos.write(data);
+ baos.write(0);
}
private String readNullTerminatedAsciiString(DataInputStream dis) throws IOException {
diff --git a/src/freenet/client/filter/M3UFilter.java b/src/freenet/client/filter/M3UFilter.java
index d94516c9e14..f66c58f4bd4 100644
--- a/src/freenet/client/filter/M3UFilter.java
+++ b/src/freenet/client/filter/M3UFilter.java
@@ -8,6 +8,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;
@@ -50,7 +51,7 @@ public class M3UFilter implements ContentDataFilter {
{ (byte)'\r' };
static final int MAX_URI_LENGTH = 16384;
static final String badUriReplacement = "#bad-uri-removed";
- private final long MAX_LENGTH_NO_PROGRESS = (100*1024*1024 * 11) / 10; // 100MiB: playlists are a different usecase, and we want to allow transparent pass-through for most files accessed via a playlist, likely through an external palyer. See FProxyToadlet.MAX_LENGTH_NO_PROGRESS for the default. This value must be synchronized with the test data!
+ private final long MAX_LENGTH_NO_PROGRESS = (200L*1024*1024 * 11) / 10; // 200MiB: playlists are a different usecase, and we want to allow transparent pass-through for most files accessed via a playlist, likely through an external palyer. See FProxyToadlet.MAX_LENGTH_NO_PROGRESS for the default. This value must be synchronized with the test data!
// TODO: Add parsing of ext-comments to allow for gapless playback.
// static final int COMMENT_EXT_SIZE = 4;
// static final byte[] COMMENT_EXT_START =
@@ -106,7 +107,7 @@ public void readFilter(
if (fileIndex <= MAX_URI_LENGTH) {
boolean lineIsEmpty = fileIndex == 0;
if (!lineIsEmpty) {
- String uriold = new String(fileUri, 0, fileIndex, "UTF-8");
+ String uriold = new String(fileUri, 0, fileIndex, StandardCharsets.UTF_8);
// System.out.println(uriold);
// clean up the URL: allow sub-m3us and mp3/ogg/flac (what we can filter)
String filtered;
@@ -156,9 +157,9 @@ public void readFilter(
filtered = badUriReplacement;
}
try {
- dos.write(filtered.getBytes("UTF-8"));
+ dos.write(filtered.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
- dos.write(badUriReplacement.getBytes("UTF-8"));
+ dos.write(badUriReplacement.getBytes(StandardCharsets.UTF_8));
}
}
// write the newline if we're not at EOF
diff --git a/src/freenet/client/filter/OggPage.java b/src/freenet/client/filter/OggPage.java
index b7f5eb4b951..4438bc62c2d 100644
--- a/src/freenet/client/filter/OggPage.java
+++ b/src/freenet/client/filter/OggPage.java
@@ -145,10 +145,10 @@ public OggPage(OggPage oldPage, Collection packets) throws IOExcept
int concludingPartialSegment = packet.payload.length % 255;
Logger.minor(this, "Whole segments: "+wholeSegments+" Partial: "+concludingPartialSegment);
for(int i = 0; i < wholeSegments; i++) {
- segmentSizes.add(Byte.valueOf(intToUnsignedByte(255)));
+ segmentSizes.add(intToUnsignedByte(255));
}
if(concludingPartialSegment != 0) {
- segmentSizes.add(Byte.valueOf(intToUnsignedByte(concludingPartialSegment)));
+ segmentSizes.add(intToUnsignedByte(concludingPartialSegment));
}
Logger.minor(this, "Writing packet sized: "+packet.payload.length);
payloadStream.write(packet.payload);
diff --git a/src/freenet/client/filter/PNGFilter.java b/src/freenet/client/filter/PNGFilter.java
index 44bb4704064..7696fb13d0b 100644
--- a/src/freenet/client/filter/PNGFilter.java
+++ b/src/freenet/client/filter/PNGFilter.java
@@ -255,8 +255,10 @@ public void readFilter(InputStream input, OutputStream output, String charset, M
if (!validChunkType) {
for (int i = 0; i < HARMLESS_CHUNK_TYPES.length; i++) {
- if (HARMLESS_CHUNK_TYPES[i].equals(chunkTypeString))
+ if (HARMLESS_CHUNK_TYPES[i].equals(chunkTypeString)) {
validChunkType = true;
+ break;
+ }
}
}
diff --git a/src/freenet/client/filter/RIFFFilter.java b/src/freenet/client/filter/RIFFFilter.java
new file mode 100644
index 00000000000..0436bb8acd3
--- /dev/null
+++ b/src/freenet/client/filter/RIFFFilter.java
@@ -0,0 +1,192 @@
+package freenet.client.filter;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.EOFException;
+import java.util.Map;
+
+import freenet.l10n.NodeL10n;
+import freenet.support.Logger;
+import freenet.support.Logger.LogLevel;
+
+/** RIFF file format filter for several formats, such as AVI, WAV, MID, and WebP
+ *
+ */
+public abstract class RIFFFilter implements ContentDataFilter {
+ private static final byte[] magicNumber = new byte[] {'R', 'I', 'F', 'F'};
+
+ @Override
+ public void readFilter(InputStream input, OutputStream output, String charset, Map otherParams,
+ String schemeHostAndPort, FilterCallback cb) throws DataFilterException, IOException {
+ DataInputStream in = new DataInputStream(input);
+ DataOutputStream out = new DataOutputStream(output);
+ for(byte magicCharacter : magicNumber) {
+ if(magicCharacter != in.readByte()) throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), l10n("invalidStream"));
+ }
+ int fileSize = readLittleEndianInt(in);
+ for(byte magicCharacter : getChunkMagicNumber()) {
+ if(magicCharacter != in.readByte()) throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), l10n("invalidStream"));
+ }
+ out.write(magicNumber);
+ if(fileSize < 0) {
+ // FIXME Video with more than 2 GiB data need unsigned format
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), l10n("data2GB"));
+ }
+ if(fileSize < 12) {
+ // There couldn't be any chunk in such a small file
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), NodeL10n.getBase().getString("ContentFilter.EOFMessage"));
+ }
+ writeLittleEndianInt(out, fileSize);
+ out.write(getChunkMagicNumber());
+
+ Object context = createContext();
+ byte[] fccType;
+ int ckSize;
+ int remainingSize = fileSize - 4;
+ try {
+ do {
+ fccType = new byte[4];
+ in.readFully(fccType);
+ ckSize = readLittleEndianInt(in);
+ if(ckSize < 0 || remainingSize < ckSize + 8 + (ckSize & 1)) {
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), l10n("dataTooBig"));
+ }
+ remainingSize -= ckSize + 8 + (ckSize & 1);
+ readFilterChunk(fccType, ckSize, context, in, out, charset, otherParams, schemeHostAndPort, cb);
+ } while(remainingSize != 0);
+ } catch(EOFException e) {
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), NodeL10n.getBase().getString("ContentFilter.EOFMessage"));
+ }
+ // Testing if there is any unprocessed bytes left
+ if(input.read() != -1) {
+ // A byte is after expected EOF
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), NodeL10n.getBase().getString("ContentFilter.EOFMessage"));
+ }
+ // Do a final test
+ if(remainingSize != 0) {
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), NodeL10n.getBase().getString("ContentFilter.EOFMessage"));
+ }
+ EOFCheck(context);
+ }
+
+ /** Get the FourCC to identify this file format
+ * @return array of four bytes
+ */
+ protected abstract byte[] getChunkMagicNumber();
+
+ /** Create a context object holding the context states
+ * @return context object
+ */
+ protected abstract Object createContext();
+
+ protected abstract void readFilterChunk(byte[] ID, int size, Object context, DataInputStream input, DataOutputStream output, String charset, Map otherParams,
+ String schemeHostAndPort, FilterCallback cb) throws DataFilterException, IOException;
+
+ /** Check for invalid conditions after EOF is reached
+ * @param context context object
+ * @throws DataFilterException
+ */
+ protected abstract void EOFCheck(Object context) throws DataFilterException;
+
+ private static String l10n(String key) {
+ return NodeL10n.getBase().getString("RIFFFilter."+key);
+ }
+
+ /** Pass through bytes to output unchanged
+ * @param in Input stream
+ * @param out Output stream
+ * @param size Number of bytes to copy
+ * @throws DataFilterException
+ * @throws IOException
+ */
+ protected void passthroughBytes(DataInputStream in, DataOutputStream out, int size) throws DataFilterException, IOException {
+ if(size < 0)
+ {
+ if(Logger.shouldLog(LogLevel.WARNING, this.getClass())) Logger.warning(this, "RIFF block size " + size + " is less than 0");
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), l10n("dataTooBig"));
+ } else {
+ // Copy 1MB at a time instead of all at once
+ int section;
+ int remaining = size;
+ if(remaining > 1024 * 1024) {
+ section = 1024 * 1024;
+ } else {
+ section = remaining;
+ }
+ byte[] buf = new byte[section];
+ while(remaining > 0) {
+ if(remaining > 1024 * 1024) {
+ section = 1024 * 1024;
+ } else {
+ section = remaining;
+ }
+ in.readFully(buf, 0, section);
+ out.write(buf, 0, section);
+ remaining -= section;
+ }
+ }
+ }
+
+ /** Write a JUNK chunk for unsupported data
+ * @param in Input stream
+ * @param out Output stream
+ * @param size Size of the chunk, if the size is odd, a padding is added
+ * @throws DataFilterException
+ * @throws IOException
+ */
+ protected void writeJunkChunk(DataInputStream in, DataOutputStream out, int size) throws DataFilterException, IOException {
+ size += size % 2; // Add a padding if necessary
+ if(in.skip(size) < size) {
+ // EOFException?
+ throw new EOFException();
+ }
+ if(size < 0)
+ {
+ if(Logger.shouldLog(LogLevel.WARNING, this.getClass())) Logger.warning(this, "RIFF block size " + size + " is less than 0");
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), l10n("dataTooBig"));
+ } else {
+ // Write 1MB at a time instead of all at once
+ int section;
+ int remaining = size;
+ byte[] zeros = new byte[1024 * 1024];
+ for(int i = 0; i < 1024 * 1024; i++) {
+ zeros[i] = 0;
+ }
+ byte[] JUNK = new byte[] {'J', 'U', 'N', 'K'};
+ out.write(JUNK);
+ writeLittleEndianInt(out, size);
+ while(remaining > 0) {
+ if(remaining > 1024 * 1024) {
+ section = 1024 * 1024;
+ } else {
+ section = remaining;
+ }
+ out.write(zeros, 0, section);
+ remaining -= section;
+ }
+ }
+ }
+
+ /** Read a little endian int. readInt and writeInt are big endian, but RIFF use little endian
+ * @param stream Stream to read from
+ * @return
+ * @throws IOException
+ */
+ protected final static int readLittleEndianInt(DataInputStream stream) throws IOException {
+ int a;
+ a = stream.readInt();
+ return Integer.reverseBytes(a);
+ }
+
+ /** Write a little endian int
+ * @param stream Stream to write to
+ * @param a
+ * @throws IOException
+ */
+ protected final static void writeLittleEndianInt(DataOutputStream stream, int a) throws IOException {
+ stream.writeInt(Integer.reverseBytes(a));
+ }
+}
diff --git a/src/freenet/client/filter/VP8PacketFilter.java b/src/freenet/client/filter/VP8PacketFilter.java
new file mode 100644
index 00000000000..5151ecd7e57
--- /dev/null
+++ b/src/freenet/client/filter/VP8PacketFilter.java
@@ -0,0 +1,46 @@
+package freenet.client.filter;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+public class VP8PacketFilter {
+ private boolean isWebP;
+ public VP8PacketFilter(boolean isWebp) {
+ this.isWebP = isWebp;
+ }
+
+ public void parse(byte[] buf, int size) throws IOException {
+ try (DataInputStream input = new DataInputStream(new ByteArrayInputStream(buf))) {
+ // Reference: RFC 6386
+ // Following code is based on vp8_parse_frame_header from RFC 6386
+ int[] header = new int[6];
+ for(int i = 0; i < 6; i++)
+ header[i] = input.readUnsignedByte();
+ int sizeInHeader;
+ boolean isKeyframe;
+ int tmp = header[0] | (header[1] << 8) | (header[2] << 16);
+ isKeyframe = (tmp & 1) == 0;
+ if(!isKeyframe && isWebP) {
+ throw new DataFilterException("VP8 decode error", "VP8 decode error", "Not a keyframe in WebP image");
+ }
+ if((tmp & 0x8) != 0) { //is_experimental bit is unsupported
+ throw new DataFilterException("VP8 decode error", "VP8 decode error", "VP8 frame version is unsupported");
+ }
+ if((tmp & 0x10) == 0 && isWebP) { //is_shown must be true for a WebP image
+ throw new DataFilterException("VP8 decode error", "VP8 decode error", "WebP frame contains an image without is_shown flag");
+ }
+ sizeInHeader = (tmp >> 5) & 0x7ffff;
+ if(size <= sizeInHeader + (isKeyframe ? 10 : 3)) {
+ throw new DataFilterException("VP8 decode error", "VP8 decode error", "VP8 frame size is invalid");
+ }
+ if(isKeyframe) {
+ if(header[3] != 0x9d || header[4] != 0x01 || header[5] != 0x2a) {
+ throw new DataFilterException("VP8 decode error", "VP8 decode error", "VP8 frame sync code is invalid");
+ }
+ }
+ }
+ // Rest of video: I don't know there is an attack
+ }
+
+}
diff --git a/src/freenet/client/filter/VorbisPacketFilter.java b/src/freenet/client/filter/VorbisPacketFilter.java
index c65be4051e6..e38321de217 100644
--- a/src/freenet/client/filter/VorbisPacketFilter.java
+++ b/src/freenet/client/filter/VorbisPacketFilter.java
@@ -17,7 +17,7 @@
* @author sajack
*/
public class VorbisPacketFilter implements CodecPacketFilter {
- enum State {UNINITIALIZED, IDENTIFICATION_FOUND, COMMENT_FOUND, SETUP_FOUND};
+ enum State {UNINITIALIZED, IDENTIFICATION_FOUND, COMMENT_FOUND, SETUP_FOUND}
static final byte[] magicNumber = new byte[] {0x76, 0x6f, 0x72, 0x62, 0x69, 0x73};
State currentState = State.UNINITIALIZED;
diff --git a/src/freenet/client/filter/WebPFilter.java b/src/freenet/client/filter/WebPFilter.java
new file mode 100644
index 00000000000..e5af061cbfa
--- /dev/null
+++ b/src/freenet/client/filter/WebPFilter.java
@@ -0,0 +1,192 @@
+package freenet.client.filter;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Map;
+
+import freenet.l10n.NodeL10n;
+import freenet.support.Logger;
+import freenet.support.Logger.LogLevel;
+
+public class WebPFilter extends RIFFFilter {
+
+ //These constants are derived from mux_type.h in libwebp
+ private final int ANIMATION_FLAG = 0x00000002;
+ private final int XMP_FLAG = 0x00000004;
+ private final int EXIF_FLAG = 0x00000008;
+ private final int ALPHA_FLAG = 0x00000010;
+ private final int ICCP_FLAG = 0x00000020;
+ private final int ALL_VALID_FLAGS = 0x0000003e;
+
+ @Override
+ protected byte[] getChunkMagicNumber() {
+ return new byte[] {'W', 'E', 'B', 'P'};
+ }
+
+ class WebPFilterContext {
+ public int VP8XFlags = 0;
+ public boolean hasVP8X = false;
+ public boolean hasANIM = false;
+ public boolean hasANMF = false;
+ public boolean hasALPH = false;
+ public boolean hasVP8 = false;
+ public boolean hasVP8L = false;
+ }
+
+ @Override
+ protected Object createContext() {
+ return new WebPFilterContext();
+ }
+
+ @Override
+ protected void readFilterChunk(byte[] ID, int size, Object context, DataInputStream input, DataOutputStream output, String charset, Map otherParams,
+ String schemeHostAndPort, FilterCallback cb) throws DataFilterException, IOException {
+ boolean logDEBUG = Logger.shouldLog(LogLevel.DEBUG, this.getClass());
+ WebPFilterContext ctx = (WebPFilterContext)context;
+ if(ID[0] == 'V' && ID[1] == 'P' && ID[2] == '8' && ID[3] == ' ') {
+ // VP8 Lossy format: RFC 6386
+ // Most WebP files just contain a single chunk of this kind
+ if(ctx.hasVP8 || ctx.hasVP8L || ctx.hasANIM) {
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "Unexpected VP8 chunk was encountered");
+ }
+ if(size < 10) {
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "The VP8 chunk was too small to be valid");
+ }
+ output.write(ID);
+ if(logDEBUG) Logger.debug(this, "Passing through WebP VP8 block with " + size + " bytes.");
+ VP8PacketFilter VP8filter = new VP8PacketFilter(true);
+ // Just read 6 bytes of the header to validate
+ byte[] buf = new byte[6];
+ input.readFully(buf);
+ VP8filter.parse(buf, size);
+ writeLittleEndianInt(output, size);
+ output.write(buf);
+ passthroughBytes(input, output, size - buf.length);
+ if((size & 1) != 0) // Add padding if necessary
+ output.writeByte(input.readByte());
+ ctx.hasVP8 = true;
+ } else if(ID[0] == 'V' && ID[1] == 'P' && ID[2] == '8' && ID[3] == 'L') {
+ // VP8 Lossless format: https://chromium.googlesource.com/webm/libwebp/+/refs/tags/v1.4.0/doc/webp-lossless-bitstream-spec.txt
+ if(ctx.hasVP8 || ctx.hasVP8L || ctx.hasANIM || ctx.hasALPH) {
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "Unexpected VP8L chunk was encountered");
+ }
+ //output.write(ID);
+ //output.writeInt(((size & 0xff000000) >> 24) | ((size & 0x00ff0000) >> 8) | ((size & 0x0000ff00) << 8) | ((size & 0x000000ff) << 24));
+ // CVE-2023-4863 is an exploit for libwebp (before version 1.3.2) implementation of WebP lossless format, and that could be used in animation and alpha channel as well. This is really serious that we must not let Bad Thing happen.
+ // TODO: Check for CVE-2023-4863 exploit!
+ ctx.hasVP8L = true;
+ throw new DataFilterException(l10n("losslessUnsupportedTitle"), l10n("losslessUnsupportedTitle"), l10n("losslessUnsupported"));
+ } else if(ID[0] == 'A' && ID[1] == 'L' && ID[2] == 'P' && ID[3] == 'H') {
+ if(ctx.hasVP8L || ctx.hasANIM || ctx.hasALPH || (!ctx.hasVP8X) || ((ctx.VP8XFlags & ALPHA_FLAG) == 0)) {
+ // Only applicable to VP8 images. VP8L already has alpha channel, so does not need this.
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "Unexpected ALPH chunk was encountered");
+ }
+ if(size == 0) {
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "Unexpected empty ALPH chunk");
+ }
+ // Alpha channel
+ int flags = input.readUnsignedByte();
+ if((flags & 2) != 0) {
+ // Compression is not uncompressed
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "WebP alpha channel contains reserved bits");
+ }
+ if((flags & 0xc0) != 0) {
+ // Compression is not uncompressed
+ // TODO: Check for CVE-2023-4863 exploit!
+ throw new DataFilterException(l10n("alphUnsupportedTitle"), l10n("alphUnsupportedTitle"), l10n("alphUnsupported"));
+ }
+ output.write(ID);
+ if(logDEBUG) Logger.debug(this, "Passing through WebP ALPH block with " + size + " bytes.");
+ writeLittleEndianInt(output, size);
+ output.writeByte(flags);
+ passthroughBytes(input, output, size - 1);
+ if((size & 1) != 0) // Add padding if necessary
+ output.writeByte(input.readByte());
+ ctx.hasALPH = true;
+ } else if(ID[0] == 'A' && ID[1] == 'N' && ID[2] == 'I' && ID[3] == 'M') {
+ if(ctx.hasVP8 || ctx.hasVP8L || ctx.hasANIM) {
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "Unexpected ANIM chunk was encountered");
+ }
+ // Global animation parameters
+ //output.write(ID);
+ //output.writeInt(((size & 0xff000000) >> 24) | ((size & 0x00ff0000) >> 8) | ((size & 0x0000ff00) << 8) | ((size & 0x000000ff) << 24));
+ // TODO: Check for CVE-2023-4863 exploit!
+ ctx.hasANIM = true;
+ throw new DataFilterException(l10n("animUnsupportedTitle"), l10n("animUnsupportedTitle"), l10n("animUnsupported"));
+ } else if(ID[0] == 'A' && ID[1] == 'N' && ID[2] == 'M' && ID[3] == 'F') {
+ // Animation frame
+ if((ctx.VP8XFlags & ANIMATION_FLAG) == 0 || ctx.hasVP8 || ctx.hasVP8L || !ctx.hasANIM) {
+ // Animation frame in static WebP file - Unexpected
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "Unexpected ANMF chunk was encountered");
+ } else {
+ ctx.hasANMF = true;
+ //output.write(ID);
+ //output.writeInt(((size & 0xff000000) >> 24) | ((size & 0x00ff0000) >> 8) | ((size & 0x0000ff00) << 8) | ((size & 0x000000ff) << 24));
+ // TODO: Check for CVE-2023-4863 exploit!
+ throw new DataFilterException(l10n("animUnsupportedTitle"), l10n("animUnsupportedTitle"), l10n("animUnsupported"));
+ }
+ } else if(ID[0] == 'V' && ID[1] == 'P' && ID[2] == '8' && ID[3] == 'X') {
+ // meta information
+ if(ctx.hasVP8 || ctx.hasVP8L || ctx.hasANIM || ctx.hasVP8X) {
+ // This should be the first chunk of the file
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "Unexpected VP8X chunk was encountered");
+ }
+ ctx.VP8XFlags = readLittleEndianInt(input);
+ if((ctx.VP8XFlags & ~ALL_VALID_FLAGS) != 0) {
+ // Has reserved flags or uses unsupported image fragmentation
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "VP8X header has reserved flags");
+ }
+ if(size != 10) {
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "VP8X header is too small or too big");
+ }
+ output.write(ID);
+ writeLittleEndianInt(output, size);
+ ctx.VP8XFlags &= ~(XMP_FLAG | EXIF_FLAG | ICCP_FLAG); // removing ICCP, EXIF and XMP bits
+ writeLittleEndianInt(output, ctx.VP8XFlags);
+ ctx.hasVP8X = true;
+ byte[] widthHeight = new byte[6];
+ input.readFully(widthHeight);
+ int width;
+ int height;
+ // width and height are 24 bits
+ width = widthHeight[0] | widthHeight[1] << 8 | widthHeight [2] << 16;
+ height = widthHeight[3] | widthHeight[4] << 8 | widthHeight [5] << 16;
+ width++;
+ height++;
+ if(width > 16384 || height > 16384) {
+ // VP8 lossy format couldn't encode more than 16384 pixels in width or height. Check again when lossless format is supported.
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "WebP image size is too big");
+ }
+ output.write(widthHeight);
+ } else if(ID[0] == 'I' && ID[1] == 'C' && ID[2] == 'C' && ID[3] == 'P') {
+ // ICC Color Profile
+ if(logDEBUG) Logger.debug(this, "WebP image has ICCP block with " + size + " bytes converted into JUNK chunk.");
+ writeJunkChunk(input, output, size);
+ } else if(ID[0] == 'E' && ID[1] == 'X' && ID[2] == 'I' && ID[3] == 'F') {
+ // EXIF metadata
+ if(logDEBUG) Logger.debug(this, "WebP image has EXIF block with " + size + " bytes converted into JUNK chunk.");
+ writeJunkChunk(input, output, size);
+ } else if(ID[0] == 'X' && ID[1] == 'M' && ID[2] == 'P' && ID[3] == ' ') {
+ // XMP metadata
+ if(logDEBUG) Logger.debug(this, "WebP image has XMP block with " + size + " bytes converted into JUNK chunk.");
+ writeJunkChunk(input, output, size);
+ } else {
+ // Unknown block
+ if(logDEBUG) Logger.debug(this, "WebP image has Unknown block with " + size + " bytes converted into JUNK chunk.");
+ writeJunkChunk(input, output, size);
+ }
+ }
+
+ @Override
+ protected void EOFCheck(Object context) throws DataFilterException {
+ WebPFilterContext ctx = (WebPFilterContext)context;
+ if(ctx.hasVP8 == false && ctx.hasVP8L == false && ctx.hasANMF == false) {
+ throw new DataFilterException(l10n("invalidTitle"), l10n("invalidTitle"), "No image chunk in the WebP file is found");
+ }
+ }
+
+ private static String l10n(String key) {
+ return NodeL10n.getBase().getString("WebPFilter."+key);
+ }
+}
diff --git a/src/freenet/clients/fcp/AddPeer.java b/src/freenet/clients/fcp/AddPeer.java
index 337439816d2..8e7a033a1b0 100644
--- a/src/freenet/clients/fcp/AddPeer.java
+++ b/src/freenet/clients/fcp/AddPeer.java
@@ -13,6 +13,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import freenet.client.FetchException;
@@ -116,7 +117,7 @@ public void run(FCPConnectionHandler handler, Node node) throws MessageInvalidEx
try {
try {
FreenetURI refUri = new FreenetURI(urlString);
- HighLevelSimpleClient client = node.clientCore.makeClient(
+ HighLevelSimpleClient client = node.getClientCore().makeClient(
RequestStarter.IMMEDIATE_SPLITFILE_PRIORITY_CLASS,
true,
true);
@@ -132,7 +133,7 @@ public void run(FCPConnectionHandler handler, Node node) throws MessageInvalidEx
throw new MessageInvalidException(ProtocolErrorMessage.URL_PARSE_ERROR, "IO error while retrieving ref URL <"+urlString+">: "+e.getMessage(), identifier, false);
}
ref = new StringBuilder(ref.toString().trim());
- if("".equals(ref.toString())) {
+ if(ref.toString().isEmpty()) {
throw new MessageInvalidException(ProtocolErrorMessage.REF_PARSE_ERROR, "Error parsing ref from URL <"+urlString+ '>', identifier, false);
}
try {
@@ -146,7 +147,7 @@ public void run(FCPConnectionHandler handler, Node node) throws MessageInvalidEx
throw new MessageInvalidException(ProtocolErrorMessage.NOT_A_FILE_ERROR, "The given ref file path <"+fileString+"> is not a file", identifier, false);
}
try {
- in = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"));
+ in = new BufferedReader(new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8));
ref = new StringBuilder(1024);
String line;
while((line = in.readLine()) != null) {
@@ -160,7 +161,7 @@ public void run(FCPConnectionHandler handler, Node node) throws MessageInvalidEx
throw new MessageInvalidException(ProtocolErrorMessage.FILE_PARSE_ERROR, "IO error while retrieving ref file <"+fileString+">: "+e.getMessage(), identifier, false);
}
ref = new StringBuilder(ref.toString().trim());
- if("".equals(ref.toString())) {
+ if(ref.toString().isEmpty()) {
throw new MessageInvalidException(ProtocolErrorMessage.REF_PARSE_ERROR, "Error parsing ref from file <"+fileString+ '>', identifier, false);
}
try {
diff --git a/src/freenet/clients/fcp/BookmarkFeed.java b/src/freenet/clients/fcp/BookmarkFeed.java
index 7459eb3f91b..2b5d29af1a3 100644
--- a/src/freenet/clients/fcp/BookmarkFeed.java
+++ b/src/freenet/clients/fcp/BookmarkFeed.java
@@ -1,6 +1,6 @@
package freenet.clients.fcp;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
import freenet.keys.FreenetURI;
import freenet.support.SimpleFieldSet;
@@ -23,13 +23,10 @@ public BookmarkFeed(String header, String shortText, String text, short priority
this.URI = URI;
this.hasAnActivelink = hasAnActivelink;
final Bucket descriptionBucket;
- try {
- if(description != null)
- descriptionBucket = new ArrayBucket(description.getBytes("UTF-8"));
- else
- descriptionBucket = new NullBucket();
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
+ if (description != null) {
+ descriptionBucket = new ArrayBucket(description.getBytes(StandardCharsets.UTF_8));
+ } else {
+ descriptionBucket = new NullBucket();
}
buckets.put("Description", descriptionBucket);
diff --git a/src/freenet/clients/fcp/ClientGet.java b/src/freenet/clients/fcp/ClientGet.java
index a02167d12aa..7cb7f9e316d 100644
--- a/src/freenet/clients/fcp/ClientGet.java
+++ b/src/freenet/clients/fcp/ClientGet.java
@@ -43,7 +43,6 @@
import freenet.crypt.HashResult;
import freenet.keys.FreenetURI;
import freenet.node.NodeClientCore;
-import freenet.support.CurrentTimeUTC;
import freenet.support.LogThresholdCallback;
import freenet.support.Logger;
import freenet.support.Logger.LogLevel;
@@ -155,7 +154,7 @@ public ClientGet(PersistentRequestClient globalClient, FreenetURI uri, boolean d
prioClass,
(persistRebootOnly ? Persistence.REBOOT : Persistence.FOREVER), realTimeFlag, null, true);
- fctx = core.clientContext.getDefaultPersistentFetchContext();
+ fctx = core.getClientContext().getDefaultPersistentFetchContext();
fctx.eventProducer.addEventListener(this);
fctx.localRequestOnly = dsOnly;
fctx.ignoreStore = ignoreDS;
@@ -214,7 +213,7 @@ public ClientGet(FCPConnectionHandler handler, ClientGetMessage message,
message.priorityClass, message.persistence, message.realTimeFlag, message.clientToken, message.global);
// Create a Fetcher directly in order to get more fine-grained control,
// since the client may override a few context elements.
- fctx = core.clientContext.getDefaultPersistentFetchContext();
+ fctx = core.getClientContext().getDefaultPersistentFetchContext();
fctx.eventProducer.addEventListener(this);
// ignoreDS
fctx.localRequestOnly = message.dsOnly;
@@ -281,7 +280,7 @@ private ClientGetter makeGetter(Bucket ret) throws IOException {
private ClientGetter makeGetter(NodeClientCore core, Bucket ret) throws IOException {
if (binaryBlob && ret == null) {
- ret = core.clientContext.getBucketFactory(persistence == Persistence.FOREVER).makeBucket(fctx.maxOutputLength);
+ ret = core.getClientContext().getBucketFactory(persistence == Persistence.FOREVER).makeBucket(fctx.maxOutputLength);
}
return new ClientGetter(this,
@@ -422,7 +421,7 @@ private void trySendDataFoundOrGetFailed(FCPConnectionOutputHandler handler, Str
}
if(handler == null && persistence == Persistence.CONNECTION)
- handler = origHandler.outputHandler;
+ handler = origHandler.getOutputHandler();
if(handler != null)
handler.queue(FCPMessage.withListRequestIdentifier(msg, listRequestIdentifier));
else
@@ -442,7 +441,7 @@ private synchronized AllDataMessage getAllDataMessage() {
private void trySendAllDataMessage(FCPConnectionOutputHandler handler, String listRequestIdentifier) {
if(persistence == Persistence.CONNECTION) {
if(handler == null)
- handler = origHandler.outputHandler;
+ handler = origHandler.getOutputHandler();
}
if(handler != null) {
FCPMessage allData = FCPMessage.withListRequestIdentifier(getAllDataMessage(), listRequestIdentifier);
@@ -453,7 +452,7 @@ private void trySendAllDataMessage(FCPConnectionOutputHandler handler, String li
private void queueProgressMessageInner(FCPMessage msg, FCPConnectionOutputHandler handler, int verbosityMask) {
if(persistence == Persistence.CONNECTION && handler == null)
- handler = origHandler.outputHandler;
+ handler = origHandler.getOutputHandler();
if(handler != null)
handler.queue(msg);
else
@@ -931,7 +930,7 @@ synchronized RequestStatus getStatus() {
boolean totalFinalized = false;
int total = 0, min = 0, fetched = 0, fatal = 0, failed = 0;
// See ClientRequester.getLatestSuccess() for why this defaults to current time.
- Date latestSuccess = CurrentTimeUTC.get();
+ Date latestSuccess = new Date();
Date latestFailure = null;
if(progressPending != null) {
diff --git a/src/freenet/clients/fcp/ClientPut.java b/src/freenet/clients/fcp/ClientPut.java
index 2edc07d0818..1f095dbe118 100644
--- a/src/freenet/clients/fcp/ClientPut.java
+++ b/src/freenet/clients/fcp/ClientPut.java
@@ -7,7 +7,6 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
@@ -29,7 +28,6 @@
import freenet.keys.FreenetURI;
import freenet.node.NodeClientCore;
import freenet.support.Base64;
-import freenet.support.CurrentTimeUTC;
import freenet.support.IllegalBase64Exception;
import freenet.support.LogThresholdCallback;
import freenet.support.Logger;
@@ -117,7 +115,7 @@ public ClientPut(PersistentRequestClient globalClient, FreenetURI uri, String id
String charset, short priorityClass, Persistence persistence, String clientToken,
boolean getCHKOnly, boolean dontCompress, int maxRetries, UploadFrom uploadFromType, File origFilename,
String contentType, RandomAccessBucket data, FreenetURI redirectTarget, String targetFilename, boolean earlyEncode, boolean canWriteClientCache, boolean forkOnCacheable, int extraInsertsSingleBlock, int extraInsertsSplitfileHeaderBlock, boolean realTimeFlag, InsertContext.CompatibilityMode compatMode, byte[] overrideSplitfileKey, boolean binaryBlob, NodeClientCore core) throws IdentifierCollisionException, NotAllowedException, MetadataUnresolvedException, IOException {
- super(uri = checkEmptySSK(uri, targetFilename, core.clientContext), identifier, verbosity, charset, null, globalClient, priorityClass, persistence, null, true, getCHKOnly, dontCompress, maxRetries, earlyEncode, canWriteClientCache, forkOnCacheable, false, extraInsertsSingleBlock, extraInsertsSplitfileHeaderBlock, realTimeFlag, null, compatMode, false/*XXX ignoreUSKDatehints*/, core);
+ super(uri = checkEmptySSK(uri, targetFilename, core.getClientContext()), identifier, verbosity, charset, null, globalClient, priorityClass, persistence, null, true, getCHKOnly, dontCompress, maxRetries, earlyEncode, canWriteClientCache, forkOnCacheable, false, extraInsertsSingleBlock, extraInsertsSplitfileHeaderBlock, realTimeFlag, null, compatMode, false/*XXX ignoreUSKDatehints*/, core);
if(uploadFromType == UploadFrom.DISK) {
if(!core.allowUploadFrom(origFilename))
throw new NotAllowedException();
@@ -140,7 +138,7 @@ public ClientPut(PersistentRequestClient globalClient, FreenetURI uri, String id
if(uploadFrom == UploadFrom.REDIRECT) {
this.targetURI = redirectTarget;
Metadata m = new Metadata(DocumentType.SIMPLE_REDIRECT, null, null, targetURI, cm);
- tempData = m.toBucket(core.clientContext.getBucketFactory(isPersistentForever()));
+ tempData = m.toBucket(core.getClientContext().getBucketFactory(isPersistentForever()));
isMetadata = true;
} else
targetURI = null;
@@ -151,11 +149,11 @@ public ClientPut(PersistentRequestClient globalClient, FreenetURI uri, String id
putter = new ClientPutter(this, data, this.uri, cm,
ctx, priorityClass,
isMetadata,
- this.uri.getDocName() == null ? targetFilename : null, binaryBlob, core.clientContext, overrideSplitfileKey, -1);
+ this.uri.getDocName() == null ? targetFilename : null, binaryBlob, core.getClientContext(), overrideSplitfileKey, -1);
}
public ClientPut(FCPConnectionHandler handler, ClientPutMessage message, FCPServer server) throws IdentifierCollisionException, MessageInvalidException, IOException {
- super(checkEmptySSK(message.uri, message.targetFilename, server.core.clientContext), message.identifier, message.verbosity, null,
+ super(checkEmptySSK(message.uri, message.targetFilename, server.getCore().getClientContext()), message.identifier, message.verbosity, null,
handler, message.priorityClass, message.persistence, message.clientToken,
message.global, message.getCHKOnly, message.dontCompress, message.localRequestOnly, message.maxRetries, message.earlyEncode, message.canWriteClientCache, message.forkOnCacheable, message.compressorDescriptor, message.extraInsertsSingleBlock, message.extraInsertsSplitfileHeaderBlock, message.realTimeFlag, message.compatibilityMode, message.ignoreUSKDatehints, server);
String salt = null;
@@ -163,7 +161,7 @@ public ClientPut(FCPConnectionHandler handler, ClientPutMessage message, FCPServ
binaryBlob = message.binaryBlob;
if(message.uploadFromType == UploadFrom.DISK) {
- if(!handler.server.core.allowUploadFrom(message.origFilename))
+ if(!handler.getServer().getCore().allowUploadFrom(message.origFilename))
throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "Not allowed to upload from "+message.origFilename, identifier, global);
if(message.fileHash != null) {
@@ -197,7 +195,7 @@ public ClientPut(FCPConnectionHandler handler, ClientPutMessage message, FCPServ
if ((mimeType == null) && (targetFilename != null)) {
mimeType = DefaultMIMETypes.guessMIMEType(targetFilename, true);
}
- if(mimeType != null && mimeType.equals("")) mimeType = null;
+ if(mimeType != null && mimeType.isEmpty()) mimeType = null;
if(mimeType != null && !DefaultMIMETypes.isPlausibleMIMEType(mimeType)) {
throw new MessageInvalidException(ProtocolErrorMessage.BAD_MIME_TYPE, "Bad MIME type in Metadata.ContentType", identifier, global);
}
@@ -211,7 +209,7 @@ public ClientPut(FCPConnectionHandler handler, ClientPutMessage message, FCPServ
this.targetURI = message.redirectTarget;
Metadata m = new Metadata(DocumentType.SIMPLE_REDIRECT, null, null, targetURI, cm);
try {
- tempData = m.toBucket(server.core.clientContext.getBucketFactory(isPersistentForever()));
+ tempData = m.toBucket(server.getCore().getClientContext().getBucketFactory(isPersistentForever()));
} catch (MetadataUnresolvedException e) {
// Impossible
Logger.error(this, "Impossible: "+e, e);
@@ -231,20 +229,16 @@ public ClientPut(FCPConnectionHandler handler, ClientPutMessage message, FCPServ
if(salt != null) {
byte[] foundHash;
MessageDigest md = SHA256.getMessageDigest();
- try {
- md.update(salt.getBytes(StandardCharsets.UTF_8));
+ md.update(salt.getBytes(StandardCharsets.UTF_8));
- try (InputStream is = data.getInputStream()) {
- SHA256.hash(is, md);
- } catch (IOException e) {
- Logger.error(this, "Got IOE: " + e.getMessage(), e);
- throw new MessageInvalidException(ProtocolErrorMessage.COULD_NOT_READ_FILE,
+ try (InputStream is = data.getInputStream()) {
+ SHA256.hash(is, md);
+ } catch (IOException e) {
+ Logger.error(this, "Got IOE: " + e.getMessage(), e);
+ throw new MessageInvalidException(ProtocolErrorMessage.COULD_NOT_READ_FILE,
"Unable to access file: " + e, identifier, global);
- }
- foundHash = md.digest();
- } finally {
- SHA256.returnMessageDigest(md);
}
+ foundHash = md.digest();
if(logMINOR) Logger.minor(this, "FileHash result : we found " + Base64.encode(foundHash) + " and were given " + Base64.encode(saltedHash) + '.');
@@ -256,7 +250,7 @@ public ClientPut(FCPConnectionHandler handler, ClientPutMessage message, FCPServ
putter = new ClientPutter(this, data, this.uri, cm,
ctx, priorityClass,
isMetadata,
- this.uri.getDocName() == null ? targetFilename : null, binaryBlob, server.core.clientContext, message.overrideSplitfileCryptoKey, message.metadataThreshold);
+ this.uri.getDocName() == null ? targetFilename : null, binaryBlob, server.getCore().getClientContext(), message.overrideSplitfileCryptoKey, message.metadataThreshold);
}
protected ClientPut() {
@@ -520,7 +514,7 @@ RequestStatus getStatus() {
int total=0, min=0, fetched=0, fatal=0, failed=0;
// See ClientRequester.getLatestSuccess() for why this defaults to current time.
- Date latestSuccess = CurrentTimeUTC.get();
+ Date latestSuccess = new Date();
Date latestFailure = null;
boolean totalFinalized = false;
diff --git a/src/freenet/clients/fcp/ClientPutBase.java b/src/freenet/clients/fcp/ClientPutBase.java
index cce1266ef45..0ec5c6e4af7 100644
--- a/src/freenet/clients/fcp/ClientPutBase.java
+++ b/src/freenet/clients/fcp/ClientPutBase.java
@@ -101,7 +101,7 @@ public ClientPutBase(FreenetURI uri, String identifier, int verbosity, String ch
FCPConnectionHandler handler, short priorityClass, Persistence persistence, String clientToken, boolean global,
boolean getCHKOnly, boolean dontCompress, boolean localRequestOnly, int maxRetries, boolean earlyEncode, boolean canWriteClientCache, boolean forkOnCacheable, String compressorDescriptor, int extraInsertsSingleBlock, int extraInsertsSplitfileHeader, boolean realTimeFlag, InsertContext.CompatibilityMode compatibilityMode, boolean ignoreUSKDatehints, FCPServer server) throws MalformedURLException {
super(uri, identifier, verbosity, charset, handler, priorityClass, persistence, realTimeFlag, clientToken, global);
- ctx = server.core.clientContext.getDefaultPersistentInsertContext();
+ ctx = server.getCore().getClientContext().getDefaultPersistentInsertContext();
ctx.getCHKOnly = getCHKOnly;
ctx.dontCompress = dontCompress;
ctx.eventProducer.addEventListener(this);
@@ -126,7 +126,7 @@ protected ClientPutBase() {
static FreenetURI checkEmptySSK(FreenetURI uri, String filename, ClientContext context) {
if("SSK".equals(uri.getKeyType()) && uri.getDocName() == null && uri.getRoutingKey() == null) {
- if(filename == null || filename.equals("")) filename = "key";
+ if(filename == null || filename.isEmpty()) filename = "key";
// SSK@ = use a random SSK.
InsertableClientSSK key = InsertableClientSSK.createRandom(context.random, "");
return key.getInsertURI().setDocName(filename);
@@ -139,7 +139,7 @@ public ClientPutBase(FreenetURI uri, String identifier, int verbosity, String ch
FCPConnectionHandler handler, PersistentRequestClient client, short priorityClass, Persistence persistence, String clientToken,
boolean global, boolean getCHKOnly, boolean dontCompress, int maxRetries, boolean earlyEncode, boolean canWriteClientCache, boolean forkOnCacheable, boolean localRequestOnly, int extraInsertsSingleBlock, int extraInsertsSplitfileHeader, boolean realTimeFlag, String compressorDescriptor, InsertContext.CompatibilityMode compatMode, boolean ignoreUSKDatehints, NodeClientCore core) throws MalformedURLException {
super(uri, identifier, verbosity, charset, handler, client, priorityClass, persistence, realTimeFlag, clientToken, global);
- ctx = core.clientContext.getDefaultPersistentInsertContext();
+ ctx = core.getClientContext().getDefaultPersistentInsertContext();
ctx.getCHKOnly = getCHKOnly;
ctx.dontCompress = dontCompress;
ctx.eventProducer.addEventListener(this);
@@ -358,7 +358,7 @@ private void trySendFinalMessage(FCPConnectionOutputHandler handler, String list
Logger.error(this, "Trying to send null message on "+this, new Exception("error"));
} else {
if(persistence == Persistence.CONNECTION && handler == null)
- handler = origHandler.outputHandler;
+ handler = origHandler.getOutputHandler();
if(handler != null)
handler.queue(FCPMessage.withListRequestIdentifier(msg, listRequestIdentifier));
else
@@ -372,7 +372,7 @@ private void trySendGeneratedURIMessage(FCPConnectionOutputHandler handler, Stri
msg = new URIGeneratedMessage(generatedURI, identifier, isGlobalQueue());
}
if(persistence == Persistence.CONNECTION && handler == null)
- handler = origHandler.outputHandler;
+ handler = origHandler.getOutputHandler();
if(handler != null)
handler.queue(FCPMessage.withListRequestIdentifier(msg, listRequestIdentifier));
else
@@ -387,7 +387,7 @@ private void trySendGeneratedURIMessage(FCPConnectionOutputHandler handler, Stri
private void trySendGeneratedMetadataMessage(Bucket metadata, FCPConnectionOutputHandler handler, String listRequestIdentifier) {
FCPMessage msg = FCPMessage.withListRequestIdentifier(new GeneratedMetadataMessage(identifier, global, metadata), listRequestIdentifier);
if(persistence == Persistence.CONNECTION && handler == null)
- handler = origHandler.outputHandler;
+ handler = origHandler.getOutputHandler();
if(handler != null)
handler.queue(msg);
else
@@ -407,7 +407,7 @@ private void trySendProgressMessage(final FCPMessage msg, final int verbosity, F
progressMessage = msg;
}
if(persistence == Persistence.CONNECTION && handler == null)
- handler = origHandler.outputHandler;
+ handler = origHandler.getOutputHandler();
if(handler != null)
handler.queue(msg);
else
diff --git a/src/freenet/clients/fcp/ClientPutComplexDirMessage.java b/src/freenet/clients/fcp/ClientPutComplexDirMessage.java
index bc9591929b7..68fca5908be 100644
--- a/src/freenet/clients/fcp/ClientPutComplexDirMessage.java
+++ b/src/freenet/clients/fcp/ClientPutComplexDirMessage.java
@@ -170,7 +170,7 @@ private void convertFilesByNameToManifestElements(HashMap filesB
convertFilesByNameToManifestElements(h, manifests, node);
} else {
DirPutFile f = (DirPutFile) val;
- if(f instanceof DiskDirPutFile && !node.clientCore.allowUploadFrom(((DiskDirPutFile)f).getFile()))
+ if(f instanceof DiskDirPutFile && !node.getClientCore().allowUploadFrom(((DiskDirPutFile)f).getFile()))
throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "Not allowed to upload "+((DiskDirPutFile) f).getFile(), identifier, global);
ManifestElement e = f.getElement();
manifestElements.put(tempName, e);
diff --git a/src/freenet/clients/fcp/ClientPutDir.java b/src/freenet/clients/fcp/ClientPutDir.java
index b55162e3c8d..0ff70122ae6 100644
--- a/src/freenet/clients/fcp/ClientPutDir.java
+++ b/src/freenet/clients/fcp/ClientPutDir.java
@@ -26,7 +26,6 @@
import freenet.clients.fcp.RequestIdentifier.RequestType;
import freenet.keys.FreenetURI;
import freenet.node.NodeClientCore;
-import freenet.support.CurrentTimeUTC;
import freenet.support.LogThresholdCallback;
import freenet.support.Logger;
import freenet.support.Logger.LogLevel;
@@ -59,7 +58,7 @@ public void shouldUpdate() {
public ClientPutDir(FCPConnectionHandler handler, ClientPutDirMessage message,
HashMap manifestElements, boolean wasDiskPut, FCPServer server) throws IdentifierCollisionException, MalformedURLException, TooManyFilesInsertException {
- super(checkEmptySSK(message.uri, message.targetFilename != null ? message.targetFilename : "site", server.core.clientContext), message.identifier, message.verbosity, null,
+ super(checkEmptySSK(message.uri, message.targetFilename != null ? message.targetFilename : "site", server.getCore().getClientContext()), message.identifier, message.verbosity, null,
handler, message.priorityClass, message.persistence, message.clientToken,
message.global, message.getCHKOnly, message.dontCompress, message.localRequestOnly, message.maxRetries, message.earlyEncode, message.canWriteClientCache, message.forkOnCacheable, message.compressorDescriptor, message.extraInsertsSingleBlock, message.extraInsertsSplitfileHeaderBlock, message.realTimeFlag, message.compatibilityMode, message.ignoreUSKDatehints, server);
logMINOR = Logger.shouldLog(LogLevel.MINOR, this);
@@ -76,7 +75,7 @@ public ClientPutDir(FCPConnectionHandler handler, ClientPutDirMessage message,
// this.manifestElements = new HashMap();
// this.manifestElements.putAll(manifestElements);
this.defaultName = message.defaultName;
- makePutter(server.core.clientContext);
+ makePutter(server.getCore().getClientContext());
if(putter != null) {
numberOfFiles = putter.countFiles();
totalSize = putter.totalSize();
@@ -94,13 +93,13 @@ public ClientPutDir(FCPConnectionHandler handler, ClientPutDirMessage message,
* @throws InsertException
*/
public ClientPutDir(PersistentRequestClient client, FreenetURI uri, String identifier, int verbosity, short priorityClass, Persistence persistence, String clientToken, boolean getCHKOnly, boolean dontCompress, int maxRetries, File dir, String defaultName, boolean allowUnreadableFiles, boolean includeHiddenFiles, boolean global, boolean earlyEncode, boolean canWriteClientCache, boolean forkOnCacheable, int extraInsertsSingleBlock, int extraInsertsSplitfileHeaderBlock, boolean realTimeFlag, byte[] overrideSplitfileCryptoKey, NodeClientCore core) throws FileNotFoundException, IdentifierCollisionException, MalformedURLException, TooManyFilesInsertException {
- super(checkEmptySSK(uri, "site", core.clientContext), identifier, verbosity , null, null, client, priorityClass, persistence, clientToken, global, getCHKOnly, dontCompress, maxRetries, earlyEncode, canWriteClientCache, forkOnCacheable, false, extraInsertsSingleBlock, extraInsertsSplitfileHeaderBlock, realTimeFlag, null, InsertContext.CompatibilityMode.COMPAT_DEFAULT, false/*XXX ignoreUSKDatehints*/, core);
+ super(checkEmptySSK(uri, "site", core.getClientContext()), identifier, verbosity , null, null, client, priorityClass, persistence, clientToken, global, getCHKOnly, dontCompress, maxRetries, earlyEncode, canWriteClientCache, forkOnCacheable, false, extraInsertsSingleBlock, extraInsertsSplitfileHeaderBlock, realTimeFlag, null, InsertContext.CompatibilityMode.COMPAT_DEFAULT, false/*XXX ignoreUSKDatehints*/, core);
wasDiskPut = true;
this.overrideSplitfileCryptoKey = overrideSplitfileCryptoKey;
logMINOR = Logger.shouldLog(LogLevel.MINOR, this);
this.manifestElements = makeDiskDirManifest(dir, "", allowUnreadableFiles, includeHiddenFiles);
this.defaultName = defaultName;
- makePutter(core.clientContext);
+ makePutter(core.getClientContext());
if(putter != null) {
numberOfFiles = putter.countFiles();
totalSize = putter.totalSize();
@@ -112,13 +111,13 @@ public ClientPutDir(PersistentRequestClient client, FreenetURI uri, String ident
}
public ClientPutDir(PersistentRequestClient client, FreenetURI uri, String identifier, int verbosity, short priorityClass, Persistence persistence, String clientToken, boolean getCHKOnly, boolean dontCompress, int maxRetries, HashMap elements, String defaultName, boolean global, boolean earlyEncode, boolean canWriteClientCache, boolean forkOnCacheable, int extraInsertsSingleBlock, int extraInsertsSplitfileHeaderBlock, boolean realTimeFlag, byte[] overrideSplitfileCryptoKey, NodeClientCore core) throws IdentifierCollisionException, MalformedURLException, TooManyFilesInsertException {
- super(checkEmptySSK(uri, "site", core.clientContext), identifier, verbosity , null, null, client, priorityClass, persistence, clientToken, global, getCHKOnly, dontCompress, maxRetries, earlyEncode, canWriteClientCache, forkOnCacheable, false, extraInsertsSingleBlock, extraInsertsSplitfileHeaderBlock, realTimeFlag, null, InsertContext.CompatibilityMode.COMPAT_DEFAULT, false/*XXX ignoreUSKDatehints*/, core);
+ super(checkEmptySSK(uri, "site", core.getClientContext()), identifier, verbosity , null, null, client, priorityClass, persistence, clientToken, global, getCHKOnly, dontCompress, maxRetries, earlyEncode, canWriteClientCache, forkOnCacheable, false, extraInsertsSingleBlock, extraInsertsSplitfileHeaderBlock, realTimeFlag, null, InsertContext.CompatibilityMode.COMPAT_DEFAULT, false/*XXX ignoreUSKDatehints*/, core);
wasDiskPut = false;
this.overrideSplitfileCryptoKey = overrideSplitfileCryptoKey;
logMINOR = Logger.shouldLog(LogLevel.MINOR, this);
this.manifestElements = elements;
this.defaultName = defaultName;
- makePutter(core.clientContext);
+ makePutter(core.getClientContext());
if(putter != null) {
numberOfFiles = putter.countFiles();
totalSize = putter.totalSize();
@@ -380,7 +379,7 @@ RequestStatus getStatus() {
int total=0, min=0, fetched=0, fatal=0, failed=0;
// See ClientRequester.getLatestSuccess() for why this defaults to current time.
- Date latestSuccess = CurrentTimeUTC.get();
+ Date latestSuccess = new Date();
Date latestFailure = null;
boolean totalFinalized = false;
diff --git a/src/freenet/clients/fcp/ClientPutDirMessage.java b/src/freenet/clients/fcp/ClientPutDirMessage.java
index a3c02d41158..7b48380a7b3 100644
--- a/src/freenet/clients/fcp/ClientPutDirMessage.java
+++ b/src/freenet/clients/fcp/ClientPutDirMessage.java
@@ -104,7 +104,7 @@ public ClientPutDirMessage(SimpleFieldSet fs) throws MessageInvalidException {
FreenetURI uu = new FreenetURI(u);
// Client is allowed to put a slash at the end if it wants to, but this is discouraged.
String[] meta = uu.getAllMetaStrings();
- if(meta != null && meta.length == 1 && meta[0].length() == 0)
+ if(meta != null && meta.length == 1 && meta[0].isEmpty())
uu = uu.setMetaString(null);
uri = uu;
} catch (MalformedURLException e) {
diff --git a/src/freenet/clients/fcp/ClientPutDiskDirMessage.java b/src/freenet/clients/fcp/ClientPutDiskDirMessage.java
index 18ab4c2015c..8c2910015e5 100644
--- a/src/freenet/clients/fcp/ClientPutDiskDirMessage.java
+++ b/src/freenet/clients/fcp/ClientPutDiskDirMessage.java
@@ -67,7 +67,7 @@ public String getName() {
@Override
public void run(FCPConnectionHandler handler, Node node)
throws MessageInvalidException {
- if(!handler.server.core.allowUploadFrom(dirname))
+ if(!handler.getServer().getCore().allowUploadFrom(dirname))
throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "Not allowed to upload from "+dirname, identifier, global);
// Create a directory listing of Buckets of data, mapped to ManifestElement's.
// Directories are sub-HashMap's.
@@ -93,7 +93,7 @@ private HashMap makeBucketsByName(File thisdir, String prefix) t
for(int i = 0 ; i < filelist.length ; i++) {
if(filelist[i].isHidden() && !includeHiddenFiles) continue;
// Skip unreadable files and dirs
- // Skip files nonexistant (dangling symlinks) - check last
+ // Skip files nonexistent (dangling symlinks) - check last
if (filelist[i].canRead() && filelist[i].exists()) {
if (filelist[i].isFile()) {
File f = filelist[i];
diff --git a/src/freenet/clients/fcp/ClientPutMessage.java b/src/freenet/clients/fcp/ClientPutMessage.java
index a6c7cc0b43d..f749c576b58 100644
--- a/src/freenet/clients/fcp/ClientPutMessage.java
+++ b/src/freenet/clients/fcp/ClientPutMessage.java
@@ -232,7 +232,7 @@ public ClientPutMessage(SimpleFieldSet fs) throws MessageInvalidException {
if(fnam != null && fnam.indexOf('/') > -1) {
throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "TargetFilename must not contain slashes", identifier, global);
}
- if(fnam != null && fnam.length() == 0) {
+ if(fnam != null && fnam.isEmpty()) {
fnam = null; // Deliberate override to tell us not to create one.
}
if(uri.getRoutingKey() == null && !uri.isKSK())
@@ -327,8 +327,8 @@ String getIdentifier() {
@Override
RandomAccessBucket createBucket(BucketFactory bf, long length, FCPServer server) throws IOException, PersistenceDisabledException {
if(persistence == Persistence.FOREVER) {
- if(server.core.killedDatabase()) throw new PersistenceDisabledException();
- return server.core.persistentTempBucketFactory.makeBucket(length);
+ if(server.getCore().killedDatabase()) throw new PersistenceDisabledException();
+ return server.getCore().getPersistentTempBucketFactory().makeBucket(length);
} else {
return super.createBucket(bf, length, server);
}
diff --git a/src/freenet/clients/fcp/ClientRequest.java b/src/freenet/clients/fcp/ClientRequest.java
index c8488b00e2a..9d450d0f2a7 100644
--- a/src/freenet/clients/fcp/ClientRequest.java
+++ b/src/freenet/clients/fcp/ClientRequest.java
@@ -140,7 +140,7 @@ public ClientRequest(FreenetURI uri2, String identifier2, int verbosity2, String
} else {
origHandler = null;
if(global) {
- client = persistence == Persistence.FOREVER ? handler.server.globalForeverClient : handler.server.globalRebootClient;
+ client = persistence == Persistence.FOREVER ? handler.getServer().getGlobalForeverClient() : handler.getServer().getGlobalRebootClient();
this.verbosity = Integer.MAX_VALUE;
clientName = null;
} else {
@@ -334,7 +334,7 @@ public void modifyRequest(String newClientToken, short newPriorityClass, FCPServ
if(newPriorityClass >= 0 && newPriorityClass != priorityClass) {
this.priorityClass = newPriorityClass;
ClientRequester r = getClientRequest();
- r.setPriorityClass(priorityClass, server.core.clientContext);
+ r.setPriorityClass(priorityClass, server.getCore().getClientContext());
priorityClassChanged = true;
if(client != null) {
RequestStatusCache cache = client.getRequestStatusCache();
@@ -348,7 +348,7 @@ public void modifyRequest(String newClientToken, short newPriorityClass, FCPServ
return; // quick return, nothing was changed
}
- server.core.clientContext.jobRunner.setCheckpointASAP();
+ server.getCore().getClientContext().jobRunner.setCheckpointASAP();
// this could become too complex with more parameters, but for now its ok
final PersistentRequestModifiedMessage modifiedMsg;
@@ -375,7 +375,7 @@ public void restartAsync(final FCPServer server, final boolean disableFilterData
}
}
if(persistence == Persistence.FOREVER) {
- server.core.clientContext.jobRunner.queue(new PersistentJob() {
+ server.getCore().getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public boolean run(ClientContext context) {
@@ -389,7 +389,7 @@ public boolean run(ClientContext context) {
}, NativeThread.HIGH_PRIORITY);
} else {
- server.core.getExecutor().execute(new PrioRunnable() {
+ server.getCore().getExecutor().execute(new PrioRunnable() {
@Override
public int getPriority() {
@@ -399,7 +399,7 @@ public int getPriority() {
@Override
public void run() {
try {
- restart(server.core.clientContext, disableFilterData);
+ restart(server.getCore().getClientContext(), disableFilterData);
} catch (PersistenceDisabledException e) {
// Impossible
}
diff --git a/src/freenet/clients/fcp/ConfigData.java b/src/freenet/clients/fcp/ConfigData.java
index dfcfac4b16c..6b0eea13591 100644
--- a/src/freenet/clients/fcp/ConfigData.java
+++ b/src/freenet/clients/fcp/ConfigData.java
@@ -39,49 +39,49 @@ public ConfigData(Node node, boolean withCurrent, boolean withDefaults, boolean
public SimpleFieldSet getFieldSet() {
SimpleFieldSet fs = new SimpleFieldSet(true);
if(withCurrent) {
- SimpleFieldSet current = node.config.exportFieldSet(Config.RequestType.CURRENT_SETTINGS, true);
+ SimpleFieldSet current = node.getConfig().exportFieldSet(Config.RequestType.CURRENT_SETTINGS, true);
if(!current.isEmpty()) {
fs.put("current", current);
}
}
if(withDefaults) {
- SimpleFieldSet defaultSettings = node.config.exportFieldSet(Config.RequestType.DEFAULT_SETTINGS, false);
+ SimpleFieldSet defaultSettings = node.getConfig().exportFieldSet(Config.RequestType.DEFAULT_SETTINGS, false);
if(!defaultSettings.isEmpty()) {
fs.put("default", defaultSettings);
}
}
if(withSortOrder) {
- SimpleFieldSet sortOrder = node.config.exportFieldSet(Config.RequestType.SORT_ORDER, false);
+ SimpleFieldSet sortOrder = node.getConfig().exportFieldSet(Config.RequestType.SORT_ORDER, false);
if(!sortOrder.isEmpty()) {
fs.put("sortOrder", sortOrder);
}
}
if(withExpertFlag) {
- SimpleFieldSet expertFlag = node.config.exportFieldSet(Config.RequestType.EXPERT_FLAG, false);
+ SimpleFieldSet expertFlag = node.getConfig().exportFieldSet(Config.RequestType.EXPERT_FLAG, false);
if(!expertFlag.isEmpty()) {
fs.put("expertFlag", expertFlag);
}
}
if(withForceWriteFlag) {
- SimpleFieldSet forceWriteFlag = node.config.exportFieldSet(Config.RequestType.FORCE_WRITE_FLAG, false);
+ SimpleFieldSet forceWriteFlag = node.getConfig().exportFieldSet(Config.RequestType.FORCE_WRITE_FLAG, false);
if(!forceWriteFlag.isEmpty()) {
fs.put("forceWriteFlag", forceWriteFlag);
}
}
if(withShortDescription) {
- SimpleFieldSet shortDescription = node.config.exportFieldSet(Config.RequestType.SHORT_DESCRIPTION, false);
+ SimpleFieldSet shortDescription = node.getConfig().exportFieldSet(Config.RequestType.SHORT_DESCRIPTION, false);
if(!shortDescription.isEmpty()) {
fs.put("shortDescription", shortDescription);
}
}
if(withLongDescription) {
- SimpleFieldSet longDescription = node.config.exportFieldSet(Config.RequestType.LONG_DESCRIPTION, false);
+ SimpleFieldSet longDescription = node.getConfig().exportFieldSet(Config.RequestType.LONG_DESCRIPTION, false);
if(!longDescription.isEmpty()) {
fs.put("longDescription", longDescription);
}
}
if(withDataTypes) {
- SimpleFieldSet type = node.config.exportFieldSet(Config.RequestType.DATA_TYPE, false);
+ SimpleFieldSet type = node.getConfig().exportFieldSet(Config.RequestType.DATA_TYPE, false);
if(!type.isEmpty()) {
fs.put("dataType", type);
}
diff --git a/src/freenet/clients/fcp/DirPutFile.java b/src/freenet/clients/fcp/DirPutFile.java
index adaaa4eb434..f261745e40b 100644
--- a/src/freenet/clients/fcp/DirPutFile.java
+++ b/src/freenet/clients/fcp/DirPutFile.java
@@ -50,7 +50,7 @@ public static DirPutFile create(SimpleFieldSet subset, String identifier, boolea
if(name == null)
throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "Missing field Name", identifier, global);
String contentTypeOverride = subset.get("Metadata.ContentType");
- if(contentTypeOverride != null && (!contentTypeOverride.equals("")) && !DefaultMIMETypes.isPlausibleMIMEType(contentTypeOverride)) {
+ if(contentTypeOverride != null && !contentTypeOverride.isEmpty() && !DefaultMIMETypes.isPlausibleMIMEType(contentTypeOverride)) {
throw new MessageInvalidException(ProtocolErrorMessage.BAD_MIME_TYPE, "Bad MIME type in Metadata.ContentType", identifier, global);
}
String type = subset.get("UploadFrom");
diff --git a/src/freenet/clients/fcp/FCPConnectionHandler.java b/src/freenet/clients/fcp/FCPConnectionHandler.java
index ecfe0966f46..51a7a5881a6 100644
--- a/src/freenet/clients/fcp/FCPConnectionHandler.java
+++ b/src/freenet/clients/fcp/FCPConnectionHandler.java
@@ -67,10 +67,27 @@ public static class DDACheckJob {
}
}
+ /**
+ * @deprecated Use {@link #getServer()} instead of accessing this directly.
+ */
+ @Deprecated
+ /* it’s not actually the field that is deprecated but accessing it directly is. */
final FCPServer server;
+
+ /**
+ * @deprecated Use {@link #getSocket()} instead of accessing this directly.
+ */
+ @Deprecated
+ /* it’s not actually the field that is deprecated but accessing it directly is. */
final Socket sock;
final FCPConnectionInputHandler inputHandler;
final Map uskSubscriptions;
+
+ /**
+ * @deprecated Use {@link #getOutputHandler()} instead of accessing this directly.
+ */
+ @Deprecated
+ /* it’s not actually the field that is deprecated but accessing it directly is. */
public final FCPConnectionOutputHandler outputHandler;
private boolean isClosed;
private boolean inputClosed;
@@ -140,14 +157,14 @@ public FCPConnectionHandler(Socket s, FCPServer server) {
this.sock = s;
this.server = server;
isClosed = false;
- this.bf = server.core.tempBucketFactory;
+ this.bf = server.getCore().getTempBucketFactory();
requestsByIdentifier = new HashMap();
uskSubscriptions = new HashMap();
this.inputHandler = new FCPConnectionInputHandler(this);
this.outputHandler = new FCPConnectionOutputHandler(this);
byte[] identifier = new byte[16];
- server.node.random.nextBytes(identifier);
+ server.getNode().getRandom().nextBytes(identifier);
this.connectionIdentifier = HexUtil.bytesToHex(identifier);
// The random 16-byte identifier was used before we added the UUID. Luckily, UUIDs are also
@@ -197,12 +214,12 @@ public void close() {
dupe = killedDupe;
}
for(ClientRequest req : requests)
- req.onLostConnection(server.core.clientContext);
+ req.onLostConnection(server.getCore().getClientContext());
for(SubscribeUSK sub : uskSubscriptions2)
sub.unsubscribe();
if(!dupe) {
try {
- server.core.clientContext.jobRunner.queue(new PersistentJob() {
+ server.getCore().getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public boolean run(ClientContext context) {
@@ -268,17 +285,17 @@ public void closedOutput() {
public void setClientName(final String name) {
this.clientName = name;
- rebootClient = server.registerRebootClient(name, server.core, this);
- rebootClient.queuePendingMessagesOnConnectionRestartAsync(outputHandler, server.core.clientContext);
+ rebootClient = server.registerRebootClient(name, server.getCore(), this);
+ rebootClient.queuePendingMessagesOnConnectionRestartAsync(outputHandler, server.getCore().getClientContext());
// Create foreverClient lazily. Everything that needs it (especially creating ClientGet's etc) runs on a database job.
if(logMINOR)
Logger.minor(this, "Set client name: "+name);
- PersistentRequestClient client = server.getForeverClient(name, server.core, this);
+ PersistentRequestClient client = server.getForeverClient(name, server.getCore(), this);
if(client != null) {
synchronized(this) {
foreverClient = client;
}
- foreverClient.queuePendingMessagesOnConnectionRestartAsync(outputHandler, server.core.clientContext);
+ foreverClient.queuePendingMessagesOnConnectionRestartAsync(outputHandler, server.getCore().getClientContext());
}
}
@@ -286,12 +303,12 @@ protected PersistentRequestClient createForeverClient(String name) {
synchronized(FCPConnectionHandler.this) {
if(foreverClient != null) return foreverClient;
}
- PersistentRequestClient client = server.registerForeverClient(name, server.core, FCPConnectionHandler.this);
+ PersistentRequestClient client = server.registerForeverClient(name, server.getCore(), FCPConnectionHandler.this);
synchronized(FCPConnectionHandler.this) {
foreverClient = client;
FCPConnectionHandler.this.notifyAll();
}
- client.queuePendingMessagesOnConnectionRestartAsync(outputHandler, server.core.clientContext);
+ client.queuePendingMessagesOnConnectionRestartAsync(outputHandler, server.getCore().getClientContext());
return foreverClient;
}
@@ -322,17 +339,17 @@ public void startClientGet(final ClientGetMessage message) {
try {
if(!persistent) {
- cg = new ClientGet(this, message, server.core);
+ cg = new ClientGet(this, message, server.getCore());
requestsByIdentifier.put(id, cg);
} else if(message.persistence == Persistence.FOREVER) {
try {
- server.core.clientContext.jobRunner.queue(new PersistentJob() {
+ server.getCore().getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public boolean run(ClientContext context) {
ClientGet getter;
try {
- getter = new ClientGet(FCPConnectionHandler.this, message, server.core);
+ getter = new ClientGet(FCPConnectionHandler.this, message, server.getCore());
} catch (IdentifierCollisionException e1) {
Logger.normal(this, "Identifier collision on "+this);
FCPMessage msg = new IdentifierCollisionMessage(id, message.global);
@@ -361,7 +378,7 @@ public boolean run(ClientContext context) {
}
return; // Don't run the start() below
} else {
- cg = new ClientGet(this, message, server.core);
+ cg = new ClientGet(this, message, server.getCore());
}
} catch (IdentifierCollisionException e) {
success = false;
@@ -383,7 +400,7 @@ public boolean run(ClientContext context) {
outputHandler.queue(msg);
return;
} else {
- cg.start(server.core.clientContext);
+ cg.start(server.getCore().getClientContext());
}
}
@@ -423,7 +440,7 @@ public void startClientPut(final ClientPutMessage message) {
}
} else if(message.persistence == Persistence.FOREVER) {
try {
- server.core.clientContext.jobRunner.queue(new PersistentJob() {
+ server.getCore().getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public boolean run(ClientContext context) {
@@ -498,7 +515,7 @@ public boolean run(ClientContext context) {
return;
} else {
Logger.minor(this, "Starting "+cp);
- cp.start(server.core.clientContext);
+ cp.start(server.getCore().getClientContext());
}
}
@@ -536,7 +553,7 @@ public void startClientPutDir(final ClientPutDirMessage message, final HashMapfcpConnectionHandler.outputHandler.queue(...)
* with fcpConnectionHandler.send(...)
* TODO: The deprecation is merely to enforce people to stop using the said member variable
* in a public way. The function itself is fine to stay. Once the public usage has been
* replaced by the suggested way of using send(), please make the member variable
- * {@link FCPConnectionHandler#outputHandler} private and remove the deprecation at this
+ * {@link FCPConnectionHandler#getOutputHandler()} private and remove the deprecation at this
* function here.
*/
@Deprecated
@@ -137,8 +137,8 @@ public void queue(FCPMessage msg) {
if(logDEBUG)
Logger.debug(this, "Queueing "+msg, new Exception("debug"));
if(msg == null) throw new NullPointerException();
- boolean neverDropAMessage = handler.server.neverDropAMessage();
- int MAX_QUEUE_LENGTH = handler.server.maxMessageQueueLength();
+ boolean neverDropAMessage = handler.getServer().neverDropAMessage();
+ int MAX_QUEUE_LENGTH = handler.getServer().maxMessageQueueLength();
synchronized(outQueue) {
if(closedOutputQueue) {
Logger.error(this, "Closed already: "+this+" queueing message "+msg);
@@ -176,7 +176,7 @@ public void onClosed() {
}
public boolean isQueueHalfFull() {
- int MAX_QUEUE_LENGTH = handler.server.maxMessageQueueLength();
+ int MAX_QUEUE_LENGTH = handler.getServer().maxMessageQueueLength();
synchronized(outQueue) {
return outQueue.size() > MAX_QUEUE_LENGTH / 2;
}
diff --git a/src/freenet/clients/fcp/FCPMessage.java b/src/freenet/clients/fcp/FCPMessage.java
index 4f1028fc954..c6caf63f0b4 100644
--- a/src/freenet/clients/fcp/FCPMessage.java
+++ b/src/freenet/clients/fcp/FCPMessage.java
@@ -2,6 +2,7 @@
import java.io.IOException;
import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
import freenet.node.Node;
import freenet.support.LogThresholdCallback;
@@ -53,8 +54,8 @@ public void send(OutputStream os) throws IOException {
}
sfs.setEndMarker(getEndString());
String msg = sfs.toString();
- os.write((getName()+ '\n').getBytes("UTF-8"));
- os.write(msg.getBytes("UTF-8"));
+ os.write((getName()+ '\n').getBytes(StandardCharsets.UTF_8));
+ os.write(msg.getBytes(StandardCharsets.UTF_8));
if(logDEBUG) {
Logger.debug(this, "Outgoing FCP message:\n"+getName()+'\n'+sfs.toString());
Logger.debug(this, "Being handled by "+this);
@@ -93,8 +94,8 @@ public static FCPMessage create(String name, SimpleFieldSet fs, BucketFactory bf
return new SendTextMessage(fs);
if(name.equals(DisconnectMessage.NAME))
return new DisconnectMessage(fs);
- if(name.equals(FCPPluginClientMessage.NAME))
- return new FCPPluginClientMessage(fs);
+ if(name.equals(FCPPluginClientMessage.NAME))
+ return new FCPPluginClientMessage(fs);
if(name.equals(GenerateSSKMessage.NAME))
return new GenerateSSKMessage(fs);
if(name.equals(GetConfig.NAME))
diff --git a/src/freenet/clients/fcp/FCPPluginMessage.java b/src/freenet/clients/fcp/FCPPluginMessage.java
index 23773a4b575..190372ea19c 100644
--- a/src/freenet/clients/fcp/FCPPluginMessage.java
+++ b/src/freenet/clients/fcp/FCPPluginMessage.java
@@ -26,8 +26,8 @@ public static enum ClientPermissions {
* plugin is running inside the node, it can probably do whatever it wants. We're
* nevertheless shipping this information to you as it is available anyway. */
ACCESS_DIRECT
- };
-
+ }
+
/**
* The permissions of the client which sent the messages. Null for server-to-client and
* outgoing messages.
diff --git a/src/freenet/clients/fcp/FCPServer.java b/src/freenet/clients/fcp/FCPServer.java
index 86e37f00b16..e9a4b77490b 100644
--- a/src/freenet/clients/fcp/FCPServer.java
+++ b/src/freenet/clients/fcp/FCPServer.java
@@ -64,10 +64,28 @@ public class FCPServer implements Runnable, DownloadCache {
private static boolean logMINOR;
public final static int DEFAULT_FCP_PORT = 9481;
NetworkInterface networkInterface;
+
+ /**
+ * @deprecated Use {@link #getCore()} instead of accessing this directly.
+ */
+ @Deprecated
+ /* It’s not the field that is deprecated but accessing it directly is. */
public final NodeClientCore core;
+
+ /**
+ * @deprecated Use {@link #getNode()} instead of accessing this directly.
+ */
+ @Deprecated
+ /* It’s not the field that is deprecated but accessing it directly is. */
final Node node;
final int port;
private static boolean ssl = false;
+
+ /**
+ * @deprecated Use {@link #isEnabled()} instead of accessing this directly.
+ */
+ @Deprecated
+ /* It’s not the field that is deprecated but accessing it directly is. */
public final boolean enabled;
String bindTo;
private String allowedHosts;
@@ -76,7 +94,19 @@ public class FCPServer implements Runnable, DownloadCache {
* so we don't have to bloat this class with that. */
final FCPPluginConnectionTracker pluginConnectionTracker;
final WeakHashMap rebootClientsByName;
+
+ /**
+ * @deprecated Use {@link #getGlobalRebootClient()} instead of accessing this directly.
+ */
+ @Deprecated
+ /* It’s not the field that is deprecated but accessing it directly is. */
final PersistentRequestClient globalRebootClient;
+
+ /**
+ * @deprecated Use {@link #getGlobalForeverClient()} instead of accessing this directly.
+ */
+ @Deprecated
+ /* It’s not the field that is deprecated but accessing it directly is. */
PersistentRequestClient globalForeverClient;
public static final int QUEUE_MAX_RETRIES = -1;
public static final long QUEUE_MAX_DATA_SIZE = Long.MAX_VALUE;
@@ -121,9 +151,9 @@ private void maybeGetNetworkInterface() {
NetworkInterface tempNetworkInterface = null;
try {
if(ssl) {
- tempNetworkInterface = SSLNetworkInterface.create(port, bindTo, allowedHosts, node.executor, true);
+ tempNetworkInterface = SSLNetworkInterface.create(port, bindTo, allowedHosts, node.getExecutor(), true);
} else {
- tempNetworkInterface = NetworkInterface.create(port, bindTo, allowedHosts, node.executor, true);
+ tempNetworkInterface = NetworkInterface.create(port, bindTo, allowedHosts, node.getExecutor(), true);
}
} catch (IOException be) {
Logger.error(this, "Couldn't bind to FCP Port "+bindTo+ ':' +port+". FCP Server not started.", be);
@@ -152,7 +182,7 @@ public void maybeStart() {
this.networkInterface = null;
}
- if(node.pluginManager.isEnabled()) {
+ if(node.getPluginManager().isEnabled()) {
// We need to start the FCPPluginConnectionTracker no matter whether this.enabled == true:
// If networked FCP is disabled, plugins might still communicate via non-networked
// intra-node FCP.
@@ -501,7 +531,7 @@ final FCPPluginConnectionImpl createFCPPluginConnectionForNetworkedFCP(String se
throws PluginNotFoundException {
FCPPluginConnectionImpl connection = FCPPluginConnectionImpl.constructForNetworkedFCP(
- pluginConnectionTracker, node.executor, node.pluginManager,
+ pluginConnectionTracker, node.getExecutor(), node.getPluginManager(),
serverPluginName, messageHandler);
// The constructor function already did this for us
/* pluginConnectionTracker.registerConnection(connection); */
@@ -540,7 +570,7 @@ public final FCPPluginConnection createFCPPluginConnectionForIntraNodeFCP(
throws PluginNotFoundException {
FCPPluginConnectionImpl connection = FCPPluginConnectionImpl.constructForIntraNodeFCP(
- pluginConnectionTracker, node.executor, node.pluginManager,
+ pluginConnectionTracker, node.getExecutor(), node.getPluginManager(),
serverPluginName, messageHandler);
// The constructor function already did this for us
/* pluginConnectionTracker.registerConnection(connection); */
@@ -624,10 +654,10 @@ public RequestStatus[] getGlobalRequests() throws PersistenceDisabledException {
}
public boolean removeGlobalRequestBlocking(final String identifier) throws MessageInvalidException, PersistenceDisabledException {
- if(!globalRebootClient.removeByIdentifier(identifier, true, this, core.clientContext)) {
+ if(!globalRebootClient.removeByIdentifier(identifier, true, this, core.getClientContext())) {
final CountDownLatch done = new CountDownLatch(1);
final AtomicBoolean success = new AtomicBoolean();
- core.clientContext.jobRunner.queue(new PersistentJob() {
+ core.getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public String toString() {
@@ -638,7 +668,7 @@ public String toString() {
public boolean run(ClientContext context) {
boolean succeeded = false;
try {
- succeeded = globalForeverClient.removeByIdentifier(identifier, true, FCPServer.this, core.clientContext);
+ succeeded = globalForeverClient.removeByIdentifier(identifier, true, FCPServer.this, core.getClientContext());
} catch (Throwable t) {
Logger.error(this, "Caught removing identifier "+identifier+": "+t, t);
} finally {
@@ -661,10 +691,10 @@ public boolean run(ClientContext context) {
}
public boolean removeAllGlobalRequestsBlocking() throws PersistenceDisabledException {
- globalRebootClient.removeAll(core.clientContext);
+ globalRebootClient.removeAll(core.getClientContext());
final CountDownLatch done = new CountDownLatch(1);
final AtomicBoolean success = new AtomicBoolean();
- core.clientContext.jobRunner.queue(new PersistentJob() {
+ core.getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public String toString() {
@@ -675,7 +705,7 @@ public String toString() {
public boolean run(ClientContext context) {
boolean succeeded = false;
try {
- globalForeverClient.removeAll(core.clientContext);
+ globalForeverClient.removeAll(core.getClientContext());
succeeded = true;
} catch (Throwable t) {
Logger.error(this, "Caught while processing panic: "+t, t);
@@ -711,7 +741,7 @@ class OutputWrapper {
}
final OutputWrapper ow = new OutputWrapper();
- core.clientContext.jobRunner.queue(new PersistentJob() {
+ core.getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public String toString() {
@@ -777,7 +807,7 @@ class OutputWrapper {
boolean done;
}
final OutputWrapper ow = new OutputWrapper();
- core.clientContext.jobRunner.queue(new PersistentJob() {
+ core.getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public String toString() {
@@ -865,7 +895,7 @@ public void makePersistentGlobalRequest(FreenetURI fetchURI, boolean filterData,
while(true) {
byte[] buf = new byte[8];
try {
- core.random.nextBytes(buf);
+ core.getRandom().nextBytes(buf);
String id = "FProxy:"+Base64.encode(buf);
innerMakePersistentGlobalRequest(fetchURI, filterData, persistence, returnType, id, returnFilename, realTimeFlag);
return;
@@ -879,7 +909,7 @@ public void makePersistentGlobalRequest(FreenetURI fetchURI, boolean filterData,
private File makeReturnFilename(FreenetURI uri, String expectedMimeType, File downloadsDir) {
String ext;
- if((expectedMimeType != null) && (expectedMimeType.length() > 0) &&
+ if((expectedMimeType != null) && !expectedMimeType.isEmpty() &&
!expectedMimeType.equals(DefaultMIMETypes.DEFAULT_MIME_TYPE)) {
ext = DefaultMIMETypes.getExtension(expectedMimeType);
} else ext = null;
@@ -904,14 +934,14 @@ private File makeReturnFilename(FreenetURI uri, String expectedMimeType, File do
private void innerMakePersistentGlobalRequest(FreenetURI fetchURI, boolean filterData, boolean persistRebootOnly, ReturnType returnType, String id, File returnFilename,
boolean realTimeFlag) throws IdentifierCollisionException, NotAllowedException, IOException {
- FetchContext defaultFetchContext = core.clientContext.getDefaultPersistentFetchContext();
+ FetchContext defaultFetchContext = core.getClientContext().getDefaultPersistentFetchContext();
final ClientGet cg =
new ClientGet(persistRebootOnly ? globalRebootClient : globalForeverClient, fetchURI, defaultFetchContext.localRequestOnly,
defaultFetchContext.ignoreStore, filterData, QUEUE_MAX_RETRIES,
QUEUE_MAX_RETRIES, QUEUE_MAX_DATA_SIZE, returnType, persistRebootOnly, id,
Integer.MAX_VALUE, RequestStarter.BULK_SPLITFILE_PRIORITY_CLASS, returnFilename, null, false, realTimeFlag, false, core);
cg.register(false);
- cg.start(core.clientContext);
+ cg.start(core.getClientContext());
}
/**
@@ -958,14 +988,14 @@ public void setCompletionCallback(RequestCompletionCallback cb) {
*/
public void startBlocking(final ClientRequest req, ClientContext context) throws IdentifierCollisionException, PersistenceDisabledException {
if(req.persistence == Persistence.REBOOT) {
- req.start(core.clientContext);
+ req.start(core.getClientContext());
} else {
class OutputWrapper {
boolean done;
IdentifierCollisionException collided;
}
final OutputWrapper ow = new OutputWrapper();
- core.clientContext.jobRunner.queue(new PersistentJob() {
+ core.getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public String toString() {
@@ -1012,7 +1042,7 @@ public boolean run(ClientContext context) {
public boolean restartBlocking(final String identifier, final boolean disableFilterData) throws PersistenceDisabledException {
ClientRequest req = globalRebootClient.getRequest(identifier);
if(req != null) {
- req.restart(core.clientContext, disableFilterData);
+ req.restart(core.getClientContext(), disableFilterData);
return true;
} else {
class OutputWrapper {
@@ -1021,7 +1051,7 @@ class OutputWrapper {
}
final OutputWrapper ow = new OutputWrapper();
if(logMINOR) Logger.minor(this, "Queueing restart of "+identifier);
- core.clientContext.jobRunner.queue(new PersistentJob() {
+ core.getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public String toString() {
@@ -1086,7 +1116,7 @@ class OutputWrapper {
final OutputWrapper ow = new OutputWrapper();
- core.clientContext.jobRunner.queue(new PersistentJob() {
+ core.getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public String toString() {
@@ -1155,7 +1185,7 @@ public CacheFetchResult lookupInstant(FreenetURI key, boolean noFilter, boolean
Bucket newData = null;
try {
if(preferred != null) newData = preferred;
- else newData = core.tempBucketFactory.makeBucket(origData.size());
+ else newData = core.getTempBucketFactory().makeBucket(origData.size());
BucketTools.copy(origData, newData);
if(origData.size() != newData.size()) {
Logger.normal(this, "Maybe it disappeared under us?");
@@ -1188,7 +1218,7 @@ public CacheFetchResult lookup(FreenetURI key, boolean noFilter, ClientContext c
if(preferred != null)
newData = preferred;
else
- newData = core.tempBucketFactory.makeBucket(origData.size());
+ newData = core.getTempBucketFactory().makeBucket(origData.size());
BucketTools.copy(origData, newData);
} catch (IOException e) {
Logger.error(this, "Unable to copy data: "+e, e);
@@ -1200,4 +1230,20 @@ public CacheFetchResult lookup(FreenetURI key, boolean noFilter, ClientContext c
return null;
}
+ public NodeClientCore getCore() {
+ return core;
+ }
+
+ public Node getNode() {
+ return node;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public PersistentRequestClient getGlobalRebootClient() {
+ return globalRebootClient;
+ }
+
}
diff --git a/src/freenet/clients/fcp/FeedMessage.java b/src/freenet/clients/fcp/FeedMessage.java
index ef9af3a7d80..b19dc7841ef 100644
--- a/src/freenet/clients/fcp/FeedMessage.java
+++ b/src/freenet/clients/fcp/FeedMessage.java
@@ -1,6 +1,6 @@
package freenet.clients.fcp;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
import freenet.node.Node;
import freenet.support.SimpleFieldSet;
@@ -18,18 +18,14 @@ public class FeedMessage extends MultipleDataCarryingMessage {
private final long updatedTime;
public FeedMessage(String header, String shortText, String text, short priorityClass, long updatedTime) {
- this.header = header;
- this.shortText = shortText;
- this.priorityClass = priorityClass;
- this.updatedTime = updatedTime;
-
- //The text may contain newlines
- try {
- Bucket textBucket = new ArrayBucket(text.getBytes("UTF-8"));
- buckets.put("Text", textBucket);
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
- }
+ this.header = header;
+ this.shortText = shortText;
+ this.priorityClass = priorityClass;
+ this.updatedTime = updatedTime;
+
+ //The text may contain newlines
+ Bucket textBucket = new ArrayBucket(text.getBytes(StandardCharsets.UTF_8));
+ buckets.put("Text", textBucket);
}
@Override
diff --git a/src/freenet/clients/fcp/FilterMessage.java b/src/freenet/clients/fcp/FilterMessage.java
index 727444b875e..b899faefb18 100644
--- a/src/freenet/clients/fcp/FilterMessage.java
+++ b/src/freenet/clients/fcp/FilterMessage.java
@@ -10,9 +10,9 @@
import freenet.client.DefaultMIMETypes;
import freenet.client.async.ClientContext;
import freenet.client.filter.ContentFilter;
+import freenet.client.filter.ContentFilter.FilterStatus;
import freenet.client.filter.FilterOperation;
import freenet.client.filter.UnsafeContentTypeException;
-import freenet.client.filter.ContentFilter.FilterStatus;
import freenet.node.FSParseException;
import freenet.node.Node;
import freenet.support.Logger;
@@ -174,7 +174,7 @@ public void run(FCPConnectionHandler handler, Node node) throws MessageInvalidEx
InputStream input = bucket.getInputStream();
OutputStream output = resultBucket.getOutputStream()
) {
- FilterStatus status = applyFilter(input, output, handler.server.core.clientContext);
+ FilterStatus status = applyFilter(input, output, handler.getServer().getCore().getClientContext());
resultCharset = status.charset;
resultMimeType = status.mimeType;
} catch (UnsafeContentTypeException e) {
diff --git a/src/freenet/clients/fcp/GenerateSSKMessage.java b/src/freenet/clients/fcp/GenerateSSKMessage.java
index 6053d987b10..adea567135d 100644
--- a/src/freenet/clients/fcp/GenerateSSKMessage.java
+++ b/src/freenet/clients/fcp/GenerateSSKMessage.java
@@ -33,7 +33,7 @@ public String getName() {
@Override
public void run(FCPConnectionHandler handler, Node node)
throws MessageInvalidException {
- InsertableClientSSK key = InsertableClientSSK.createRandom(node.random, "");
+ InsertableClientSSK key = InsertableClientSSK.createRandom(node.getRandom(), "");
FreenetURI insertURI = key.getInsertURI();
FreenetURI requestURI = key.getURI();
SSKKeypairMessage msg = new SSKKeypairMessage(insertURI, requestURI, identifier);
diff --git a/src/freenet/clients/fcp/GetFailedMessage.java b/src/freenet/clients/fcp/GetFailedMessage.java
index 5cd446bc051..f86acb81faf 100644
--- a/src/freenet/clients/fcp/GetFailedMessage.java
+++ b/src/freenet/clients/fcp/GetFailedMessage.java
@@ -139,6 +139,7 @@ public SimpleFieldSet getFieldSet(boolean verbose) {
if(verbose)
sfs.putSingle("ShortCodeDescription", getShortFailedMessage());
sfs.putSingle("Identifier", identifier);
+ sfs.put("Global", global);
if(expectedDataLength > -1) {
sfs.put("ExpectedDataLength", expectedDataLength);
}
diff --git a/src/freenet/clients/fcp/GetPluginInfo.java b/src/freenet/clients/fcp/GetPluginInfo.java
index b4c06206e6c..6ca74cd0232 100644
--- a/src/freenet/clients/fcp/GetPluginInfo.java
+++ b/src/freenet/clients/fcp/GetPluginInfo.java
@@ -46,7 +46,7 @@ public void run(FCPConnectionHandler handler, Node node)
throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "GetPluginInfo detailed requires full access", identifier, false);
}
- PluginInfoWrapper pi = node.pluginManager.getPluginInfo(plugname);
+ PluginInfoWrapper pi = node.getPluginManager().getPluginInfo(plugname);
if (pi == null) {
handler.send(new ProtocolErrorMessage(ProtocolErrorMessage.NO_SUCH_PLUGIN, false, "Plugin '"+ plugname + "' does not exist or is not a FCP plugin", identifier, false));
} else {
diff --git a/src/freenet/clients/fcp/GetRequestStatusMessage.java b/src/freenet/clients/fcp/GetRequestStatusMessage.java
index 1255439ffec..839c75b7263 100644
--- a/src/freenet/clients/fcp/GetRequestStatusMessage.java
+++ b/src/freenet/clients/fcp/GetRequestStatusMessage.java
@@ -40,12 +40,12 @@ public void run(final FCPConnectionHandler handler, Node node)
throws MessageInvalidException {
ClientRequest req = handler.getRebootRequest(global, handler, identifier);
if(req == null) {
- if(node.clientCore.killedDatabase()) {
+ if(node.getClientCore().killedDatabase()) {
// Ignore.
return;
}
try {
- node.clientCore.clientContext.jobRunner.queue(new PersistentJob() {
+ node.getClientCore().getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public boolean run(ClientContext context) {
@@ -54,7 +54,7 @@ public boolean run(ClientContext context) {
ProtocolErrorMessage msg = new ProtocolErrorMessage(ProtocolErrorMessage.NO_SUCH_IDENTIFIER, false, null, identifier, global);
handler.send(msg);
} else {
- req.sendPendingMessages(handler.outputHandler, identifier, true, onlyData);
+ req.sendPendingMessages(handler.getOutputHandler(), identifier, true, onlyData);
}
return false;
}
@@ -65,7 +65,7 @@ public boolean run(ClientContext context) {
handler.send(msg);
}
} else {
- req.sendPendingMessages(handler.outputHandler, identifier, true, onlyData);
+ req.sendPendingMessages(handler.getOutputHandler(), identifier, true, onlyData);
}
}
diff --git a/src/freenet/clients/fcp/ListPersistentRequestsMessage.java b/src/freenet/clients/fcp/ListPersistentRequestsMessage.java
index 1a034b6610e..3c92f14b570 100644
--- a/src/freenet/clients/fcp/ListPersistentRequestsMessage.java
+++ b/src/freenet/clients/fcp/ListPersistentRequestsMessage.java
@@ -84,8 +84,8 @@ protected boolean noRunning() {
return false;
}
- };
-
+ }
+
public static abstract class TransientListJob extends ListJob implements Runnable {
final ClientContext context;
@@ -138,13 +138,13 @@ public void run(final FCPConnectionHandler handler, Node node)
PersistentRequestClient rebootClient = handler.getRebootClient();
- TransientListJob job = new TransientListJob(rebootClient, handler.outputHandler, node.clientCore.clientContext, identifier) {
+ TransientListJob job = new TransientListJob(rebootClient, handler.getOutputHandler(), node.getClientCore().getClientContext(), identifier) {
@Override
void complete(ClientContext context) {
if(handler.getRebootClient().watchGlobal) {
- PersistentRequestClient globalRebootClient = handler.server.globalRebootClient;
+ PersistentRequestClient globalRebootClient = handler.getServer().getGlobalRebootClient();
TransientListJob job = new TransientListJob(globalRebootClient, outputHandler, context, listRequestIdentifier) {
@@ -173,7 +173,7 @@ public boolean run(ClientContext context) {
@Override
void complete(ClientContext context) {
if(handler.getRebootClient().watchGlobal) {
- PersistentRequestClient globalForeverClient = handler.server.globalForeverClient;
+ PersistentRequestClient globalForeverClient = handler.getServer().getGlobalForeverClient();
PersistentListJob job = new PersistentListJob(globalForeverClient, outputHandler, context, listRequestIdentifier) {
@Override
diff --git a/src/freenet/clients/fcp/LoadPlugin.java b/src/freenet/clients/fcp/LoadPlugin.java
index 3473e762029..4b5ae675e04 100644
--- a/src/freenet/clients/fcp/LoadPlugin.java
+++ b/src/freenet/clients/fcp/LoadPlugin.java
@@ -29,8 +29,6 @@ public class LoadPlugin extends FCPMessage {
private final String pluginURL;
private final String urlType;
private final boolean store;
- private final boolean force;
- private final boolean forceHTTPS;
public LoadPlugin(SimpleFieldSet fs) throws MessageInvalidException {
identifier = fs.get("Identifier");
@@ -40,7 +38,7 @@ public LoadPlugin(SimpleFieldSet fs) throws MessageInvalidException {
if(pluginURL == null)
throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "Must contain a PluginURL field", identifier, false);
String type = fs.get("URLType");
- if ((type != null) && (type.trim().length() > 0))
+ if ((type != null) && !type.trim().isEmpty())
urlType = type.trim();
else
urlType = null;
@@ -51,21 +49,6 @@ public LoadPlugin(SimpleFieldSet fs) throws MessageInvalidException {
TYPENAME_URL.equalsIgnoreCase(urlType)))
throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Unknown URL type: '"+urlType+"'", identifier, false);
}
- String officialSource = fs.get("OfficialSource");
- if(officialSource != null) {
- if(officialSource.equalsIgnoreCase("https")) {
- force = true;
- forceHTTPS = true;
- } else if(officialSource.equalsIgnoreCase("freenet")) {
- force = true;
- forceHTTPS = false;
- } else {
- throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Unknown OfficialSource '"+officialSource+"'", identifier, false);
- }
- } else {
- force = false;
- forceHTTPS = false;
- }
store = fs.getBoolean("Store", false);
}
@@ -85,17 +68,17 @@ public void run(final FCPConnectionHandler handler, final Node node) throws Mess
throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "LoadPlugin requires full access", identifier, false);
}
- if(!node.pluginManager.isEnabled()) {
+ if(!node.getPluginManager().isEnabled()) {
handler.send(new ProtocolErrorMessage(ProtocolErrorMessage.PLUGINS_DISABLED, false, "Plugins disabled", identifier, false));
return;
}
- node.executor.execute(new Runnable() {
+ node.getExecutor().execute(new Runnable() {
@Override
public void run() {
String type = null;
if (urlType == null) {
- if (node.pluginManager.isOfficialPlugin(pluginURL) != null) {
+ if (node.getPluginManager().isOfficialPlugin(pluginURL) != null) {
type = TYPENAME_OFFICIAL;
} else if (new File(pluginURL).exists()) {
type = TYPENAME_FILE;
@@ -123,18 +106,23 @@ public void run() {
type = urlType.toLowerCase();
}
PluginInfoWrapper pi;
- if (TYPENAME_OFFICIAL.equals(type)) {
- pi = node.pluginManager.startPluginOfficial(pluginURL, store, force, forceHTTPS);
- } else if (TYPENAME_FILE.equals(type)) {
- pi = node.pluginManager.startPluginFile(pluginURL, store);
- } else if (TYPENAME_FREENET.equals(type)) {
- pi = node.pluginManager.startPluginFreenet(pluginURL, store);
- } else if (TYPENAME_URL.equals(type)) {
- pi = node.pluginManager.startPluginURL(pluginURL, store);
- } else {
- Logger.error(this, "This should really not happen!", new Exception("FIXME"));
- handler.send(new ProtocolErrorMessage(ProtocolErrorMessage.INTERNAL_ERROR, false, "This should really not happen! See logs for details.", identifier, false));
- return;
+ switch (type) {
+ case TYPENAME_OFFICIAL:
+ pi = node.getPluginManager().startPluginOfficial(pluginURL, store);
+ break;
+ case TYPENAME_FILE:
+ pi = node.getPluginManager().startPluginFile(pluginURL, store);
+ break;
+ case TYPENAME_FREENET:
+ pi = node.getPluginManager().startPluginFreenet(pluginURL, store);
+ break;
+ case TYPENAME_URL:
+ pi = node.getPluginManager().startPluginURL(pluginURL, store);
+ break;
+ default:
+ Logger.error(this, "This should really not happen!", new Exception("FIXME"));
+ handler.send(new ProtocolErrorMessage(ProtocolErrorMessage.INTERNAL_ERROR, false, "This should really not happen! See logs for details.", identifier, false));
+ return;
}
if (pi == null) {
handler.send(new ProtocolErrorMessage(ProtocolErrorMessage.NO_SUCH_PLUGIN, false, "Plugin '"+ pluginURL + "' does not exist or is not a FCP plugin", identifier, false));
diff --git a/src/freenet/clients/fcp/ModifyConfig.java b/src/freenet/clients/fcp/ModifyConfig.java
index a1acf6fda36..fd619d02c9b 100644
--- a/src/freenet/clients/fcp/ModifyConfig.java
+++ b/src/freenet/clients/fcp/ModifyConfig.java
@@ -39,7 +39,7 @@ public void run(FCPConnectionHandler handler, Node node) throws MessageInvalidEx
if(!handler.hasFullAccess()) {
throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "ModifyConfig requires full access", identifier, false);
}
- Config config = node.config;
+ Config config = node.getConfig();
boolean logMINOR = Logger.shouldLog(LogLevel.MINOR, this);
@@ -64,7 +64,7 @@ public void run(FCPConnectionHandler handler, Node node) throws MessageInvalidEx
}
}
}
- node.clientCore.storeConfig();
+ node.getClientCore().storeConfig();
handler.send(new ConfigData(node, true, false, false, false, false, false, false, false, identifier));
}
diff --git a/src/freenet/clients/fcp/ModifyPeer.java b/src/freenet/clients/fcp/ModifyPeer.java
index 86a7406fa69..55dfe593609 100644
--- a/src/freenet/clients/fcp/ModifyPeer.java
+++ b/src/freenet/clients/fcp/ModifyPeer.java
@@ -53,7 +53,7 @@ public void run(FCPConnectionHandler handler, Node node) throws MessageInvalidEx
DarknetPeerNode dpn = (DarknetPeerNode) pn;
String isDisabledString = fs.get("IsDisabled");
if(isDisabledString != null) {
- if(!isDisabledString.equals("")) {
+ if(!isDisabledString.isEmpty()) {
if(Fields.stringToBool(isDisabledString, false)) {
dpn.disablePeer();
} else {
@@ -63,25 +63,25 @@ public void run(FCPConnectionHandler handler, Node node) throws MessageInvalidEx
}
String isListenOnlyString = fs.get("IsListenOnly");
if(isListenOnlyString != null) {
- if(!isListenOnlyString.equals("")) {
+ if(!isListenOnlyString.isEmpty()) {
dpn.setListenOnly(Fields.stringToBool(isListenOnlyString, false));
}
}
String isBurstOnlyString = fs.get("IsBurstOnly");
if(isBurstOnlyString != null) {
- if(!isBurstOnlyString.equals("")) {
+ if(!isBurstOnlyString.isEmpty()) {
dpn.setBurstOnly(Fields.stringToBool(isBurstOnlyString, false));
}
}
String ignoreSourcePortString = fs.get("IgnoreSourcePort");
if(ignoreSourcePortString != null) {
- if(!ignoreSourcePortString.equals("")) {
+ if(!ignoreSourcePortString.isEmpty()) {
dpn.setIgnoreSourcePort(Fields.stringToBool(ignoreSourcePortString, false));
}
}
String allowLocalAddressesString = fs.get("AllowLocalAddresses");
if(allowLocalAddressesString != null) {
- if(!allowLocalAddressesString.equals("")) {
+ if(!allowLocalAddressesString.isEmpty()) {
dpn.setAllowLocalAddresses(Fields.stringToBool(allowLocalAddressesString, false));
}
}
diff --git a/src/freenet/clients/fcp/ModifyPersistentRequest.java b/src/freenet/clients/fcp/ModifyPersistentRequest.java
index 1f0a0e0c459..24124a86dfe 100644
--- a/src/freenet/clients/fcp/ModifyPersistentRequest.java
+++ b/src/freenet/clients/fcp/ModifyPersistentRequest.java
@@ -76,7 +76,7 @@ public void run(final FCPConnectionHandler handler, Node node)
ClientRequest req = handler.getRebootRequest(global, handler, identifier);
if(req == null) {
try {
- node.clientCore.clientContext.jobRunner.queue(new PersistentJob() {
+ node.getClientCore().getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public boolean run(ClientContext context) {
@@ -87,7 +87,7 @@ public boolean run(ClientContext context) {
handler.send(msg);
return false;
} else {
- req.modifyRequest(clientToken, priorityClass, handler.server);
+ req.modifyRequest(clientToken, priorityClass, handler.getServer());
}
return true;
}
@@ -98,7 +98,7 @@ public boolean run(ClientContext context) {
handler.send(msg);
}
} else {
- req.modifyRequest(clientToken, priorityClass, node.clientCore.getFCPServer());
+ req.modifyRequest(clientToken, priorityClass, node.getClientCore().getFCPServer());
}
}
diff --git a/src/freenet/clients/fcp/PersistentRequestClient.java b/src/freenet/clients/fcp/PersistentRequestClient.java
index da465d7b723..f6dfa114818 100644
--- a/src/freenet/clients/fcp/PersistentRequestClient.java
+++ b/src/freenet/clients/fcp/PersistentRequestClient.java
@@ -341,20 +341,20 @@ public boolean setWatchGlobal(boolean enabled, int verbosityMask, FCPServer serv
Logger.error(this, "Set watch global on global queue!: "+this, new Exception("debug"));
return false;
}
- if(server.globalForeverClient == null) return false;
+ if(server.getGlobalForeverClient() == null) return false;
if(watchGlobal && !enabled) {
- server.globalRebootClient.unwatch(this);
- server.globalForeverClient.unwatch(this);
+ server.getGlobalRebootClient().unwatch(this);
+ server.getGlobalForeverClient().unwatch(this);
watchGlobal = false;
} else if(enabled && !watchGlobal) {
- server.globalRebootClient.watch(this);
- server.globalForeverClient.watch(this);
+ server.getGlobalRebootClient().watch(this);
+ server.getGlobalForeverClient().watch(this);
FCPConnectionHandler connHandler = getConnection();
if(connHandler != null) {
if(persistence == Persistence.REBOOT)
- server.globalRebootClient.queuePendingMessagesOnConnectionRestartAsync(connHandler.outputHandler, server.core.clientContext);
+ server.getGlobalRebootClient().queuePendingMessagesOnConnectionRestartAsync(connHandler.getOutputHandler(), server.getCore().getClientContext());
else
- server.globalForeverClient.queuePendingMessagesOnConnectionRestartAsync(connHandler.outputHandler, server.core.clientContext);
+ server.getGlobalForeverClient().queuePendingMessagesOnConnectionRestartAsync(connHandler.getOutputHandler(), server.getCore().getClientContext());
}
watchGlobal = true;
}
diff --git a/src/freenet/clients/fcp/ProbeRequest.java b/src/freenet/clients/fcp/ProbeRequest.java
index b0583bcb672..f819858d6ac 100644
--- a/src/freenet/clients/fcp/ProbeRequest.java
+++ b/src/freenet/clients/fcp/ProbeRequest.java
@@ -133,6 +133,6 @@ public void onOverallBulkOutputCapacity(
handler.send(new ProbeOverallBulkOutputCapacityUsage(identifier, bandwidthClassForCapacityUsage, capacityUsage));
}
};
- node.startProbe(htl, node.random.nextLong(), type, listener);
+ node.startProbe(htl, node.getRandom().nextLong(), type, listener);
}
}
diff --git a/src/freenet/clients/fcp/PutFailedMessage.java b/src/freenet/clients/fcp/PutFailedMessage.java
index eb067d0127e..fcaacde70cb 100644
--- a/src/freenet/clients/fcp/PutFailedMessage.java
+++ b/src/freenet/clients/fcp/PutFailedMessage.java
@@ -64,7 +64,7 @@ public PutFailedMessage(SimpleFieldSet fs, boolean useVerboseFields) throws Malf
extraDescription = fs.get("ExtraDescription");
String euri = fs.get("ExpectedURI");
- if(euri != null && euri.length() > 0)
+ if(euri != null && !euri.isEmpty())
expectedURI = new FreenetURI(euri);
else
expectedURI = null;
diff --git a/src/freenet/clients/fcp/ReloadPlugin.java b/src/freenet/clients/fcp/ReloadPlugin.java
index d71c06b7d27..bce0ba3997d 100644
--- a/src/freenet/clients/fcp/ReloadPlugin.java
+++ b/src/freenet/clients/fcp/ReloadPlugin.java
@@ -49,19 +49,19 @@ public void run(final FCPConnectionHandler handler, final Node node) throws Mess
throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "LoadPlugin requires full access", identifier, false);
}
- node.executor.execute(new Runnable() {
+ node.getExecutor().execute(new Runnable() {
@Override
public void run() {
- PluginInfoWrapper pi = node.pluginManager.getPluginInfo(plugname);
+ PluginInfoWrapper pi = node.getPluginManager().getPluginInfo(plugname);
if (pi == null) {
handler.send(new ProtocolErrorMessage(ProtocolErrorMessage.NO_SUCH_PLUGIN, false, "Plugin '"+ plugname + "' does not exist or is not a FCP plugin", identifier, false));
} else {
String source = pi.getFilename();
- pi.stopPlugin(node.pluginManager, maxWaitTime, true);
+ pi.stopPlugin(node.getPluginManager(), maxWaitTime, true);
if (purge) {
- node.pluginManager.removeCachedCopy(pi.getFilename());
+ node.getPluginManager().removeCachedCopy(pi.getFilename());
}
- pi = node.pluginManager.startPluginAuto(source, store);
+ pi = node.getPluginManager().startPluginAuto(source, store);
if (pi == null) {
handler.send(new ProtocolErrorMessage(ProtocolErrorMessage.NO_SUCH_PLUGIN, false, "Plugin '"+ plugname + "' does not exist or is not a FCP plugin", identifier, false));
} else {
diff --git a/src/freenet/clients/fcp/RemovePersistentRequest.java b/src/freenet/clients/fcp/RemovePersistentRequest.java
index 5172df7347b..57e323d4250 100644
--- a/src/freenet/clients/fcp/RemovePersistentRequest.java
+++ b/src/freenet/clients/fcp/RemovePersistentRequest.java
@@ -50,7 +50,7 @@ public void run(final FCPConnectionHandler handler, Node node)
}
if(req == null) {
try {
- handler.server.core.clientContext.jobRunner.queue(new PersistentJob() {
+ handler.getServer().getCore().getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public boolean run(ClientContext context) {
diff --git a/src/freenet/clients/fcp/RemovePlugin.java b/src/freenet/clients/fcp/RemovePlugin.java
index 995bb600483..96487a99db0 100644
--- a/src/freenet/clients/fcp/RemovePlugin.java
+++ b/src/freenet/clients/fcp/RemovePlugin.java
@@ -47,16 +47,16 @@ public void run(final FCPConnectionHandler handler, final Node node) throws Mess
throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "LoadPlugin requires full access", identifier, false);
}
- node.executor.execute(new Runnable() {
+ node.getExecutor().execute(new Runnable() {
@Override
public void run() {
- PluginInfoWrapper pi = node.pluginManager.getPluginInfo(plugname);
+ PluginInfoWrapper pi = node.getPluginManager().getPluginInfo(plugname);
if (pi == null) {
handler.send(new ProtocolErrorMessage(ProtocolErrorMessage.NO_SUCH_PLUGIN, false, "Plugin '"+ plugname + "' does not exist or is not a FCP plugin", identifier, false));
} else {
- pi.stopPlugin(node.pluginManager, maxWaitTime, false);
+ pi.stopPlugin(node.getPluginManager(), maxWaitTime, false);
if (purge) {
- node.pluginManager.removeCachedCopy(pi.getFilename());
+ node.getPluginManager().removeCachedCopy(pi.getFilename());
}
handler.send(new PluginRemovedMessage(plugname, identifier));
}
diff --git a/src/freenet/clients/fcp/RequestStatus.java b/src/freenet/clients/fcp/RequestStatus.java
index 68cb114aff4..f78fa4d8dff 100644
--- a/src/freenet/clients/fcp/RequestStatus.java
+++ b/src/freenet/clients/fcp/RequestStatus.java
@@ -7,7 +7,6 @@
import freenet.clients.fcp.ClientRequest.Persistence;
import freenet.keys.FreenetURI;
import freenet.l10n.NodeL10n;
-import freenet.support.CurrentTimeUTC;
/** The status of a request. Cached copy i.e. can be accessed outside the database thread
* even for a persistent request.
@@ -41,7 +40,7 @@ public abstract class RequestStatus implements Cloneable {
/** The download or upload has finished.
* @param success Did it succeed? */
synchronized void setFinished(boolean success) {
- this.latestSuccess = CurrentTimeUTC.get();
+ this.latestSuccess = new Date();
this.hasFinished = true;
this.hasSucceeded = success;
this.hasStarted = true;
@@ -50,7 +49,7 @@ synchronized void setFinished(boolean success) {
synchronized void restart(boolean started) {
// See ClientRequester.getLatestSuccess() for why this defaults to current time.
- this.latestSuccess = CurrentTimeUTC.get();
+ this.latestSuccess = new Date();
this.hasFinished = false;
this.hasSucceeded = false;
this.hasStarted = started;
diff --git a/src/freenet/clients/fcp/SendBookmarkMessage.java b/src/freenet/clients/fcp/SendBookmarkMessage.java
index 655fd15be3b..f2371479a41 100644
--- a/src/freenet/clients/fcp/SendBookmarkMessage.java
+++ b/src/freenet/clients/fcp/SendBookmarkMessage.java
@@ -1,8 +1,8 @@
package freenet.clients.fcp;
import java.io.IOException;
-import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
+import java.nio.charset.StandardCharsets;
import freenet.keys.FreenetURI;
import freenet.node.DarknetPeerNode;
@@ -53,13 +53,10 @@ protected int handleFeed(DarknetPeerNode pn) throws MessageInvalidException {
try {
if(dataLength() > 0) {
byte[] description = BucketTools.toByteArray(bucket);
- return pn.sendBookmarkFeed(uri, name, new String(description, "UTF-8"), hasAnAnActiveLink);
+ return pn.sendBookmarkFeed(uri, name, new String(description, StandardCharsets.UTF_8), hasAnAnActiveLink);
}
else
return pn.sendBookmarkFeed(uri, name, null, hasAnAnActiveLink);
-
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
} catch (IOException e) {
throw new MessageInvalidException(ProtocolErrorMessage.INVALID_MESSAGE, "", null, false);
}
diff --git a/src/freenet/clients/fcp/SendTextMessage.java b/src/freenet/clients/fcp/SendTextMessage.java
index 4a6c9de47f9..4e1ad8bdd44 100644
--- a/src/freenet/clients/fcp/SendTextMessage.java
+++ b/src/freenet/clients/fcp/SendTextMessage.java
@@ -1,7 +1,7 @@
package freenet.clients.fcp;
import java.io.IOException;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
import freenet.node.DarknetPeerNode;
import freenet.support.SimpleFieldSet;
@@ -28,13 +28,11 @@ protected int handleFeed(DarknetPeerNode pn) throws MessageInvalidException {
try {
if(dataLength() > 0) {
byte[] text = BucketTools.toByteArray(bucket);
- return pn.sendTextFeed(new String(text, "UTF-8"));
+ return pn.sendTextFeed(new String(text, StandardCharsets.UTF_8));
}
else {
throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Invalid data length", null, false);
}
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
} catch (IOException e) {
throw new MessageInvalidException(ProtocolErrorMessage.INVALID_MESSAGE, "", null, false);
}
diff --git a/src/freenet/clients/fcp/SendURIMessage.java b/src/freenet/clients/fcp/SendURIMessage.java
index b8e425a81c0..ec68d61e433 100644
--- a/src/freenet/clients/fcp/SendURIMessage.java
+++ b/src/freenet/clients/fcp/SendURIMessage.java
@@ -1,8 +1,8 @@
package freenet.clients.fcp;
import java.io.IOException;
-import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
+import java.nio.charset.StandardCharsets;
import freenet.keys.FreenetURI;
import freenet.node.DarknetPeerNode;
@@ -41,12 +41,10 @@ protected int handleFeed(DarknetPeerNode pn) throws MessageInvalidException {
try {
if(dataLength() > 0) {
byte[] description = BucketTools.toByteArray(bucket);
- return pn.sendDownloadFeed(uri, new String(description, "UTF-8"));
+ return pn.sendDownloadFeed(uri, new String(description, StandardCharsets.UTF_8));
}
else
return pn.sendDownloadFeed(uri, null);
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
} catch (IOException e) {
throw new MessageInvalidException(ProtocolErrorMessage.INVALID_MESSAGE, "", null, false);
}
diff --git a/src/freenet/clients/fcp/SubscribeUSK.java b/src/freenet/clients/fcp/SubscribeUSK.java
index b1aa3553d81..839ffd2f376 100644
--- a/src/freenet/clients/fcp/SubscribeUSK.java
+++ b/src/freenet/clients/fcp/SubscribeUSK.java
@@ -31,10 +31,10 @@ public SubscribeUSK(SubscribeUSKMessage message, NodeClientCore core, FCPConnect
prioProgress = message.prioProgress;
handler.addUSKSubscription(identifier, this);
if((!message.dontPoll) && message.sparsePoll)
- toUnsub = core.uskManager.subscribeSparse(message.key, this, message.ignoreUSKDatehints,
+ toUnsub = core.getUskManager().subscribeSparse(message.key, this, message.ignoreUSKDatehints,
handler.getRebootClient().lowLevelClient(message.realTimeFlag));
else {
- core.uskManager.subscribe(message.key, this, !message.dontPoll, message.ignoreUSKDatehints,
+ core.getUskManager().subscribe(message.key, this, !message.dontPoll, message.ignoreUSKDatehints,
handler.getRebootClient().lowLevelClient(message.realTimeFlag));
toUnsub = this;
}
@@ -43,7 +43,7 @@ public SubscribeUSK(SubscribeUSKMessage message, NodeClientCore core, FCPConnect
@Override
public void onFoundEdition(long l, USK key, ClientContext context, boolean wasMetadata, short codec, byte[] data, boolean newKnownGood, boolean newSlotToo) {
if(handler.isClosed()) {
- core.uskManager.unsubscribe(key, toUnsub);
+ core.getUskManager().unsubscribe(key, toUnsub);
return;
}
//if(newKnownGood && !newSlotToo) return;
@@ -62,7 +62,7 @@ public short getPollingPriorityProgress() {
}
public void unsubscribe() {
- core.uskManager.unsubscribe(usk, toUnsub);
+ core.getUskManager().unsubscribe(usk, toUnsub);
}
@Override
diff --git a/src/freenet/clients/fcp/SubscribeUSKMessage.java b/src/freenet/clients/fcp/SubscribeUSKMessage.java
index bb46dec88aa..943965469a0 100644
--- a/src/freenet/clients/fcp/SubscribeUSKMessage.java
+++ b/src/freenet/clients/fcp/SubscribeUSKMessage.java
@@ -77,7 +77,7 @@ public String getName() {
public void run(FCPConnectionHandler handler, Node node)
throws MessageInvalidException {
try {
- new SubscribeUSK(this, node.clientCore, handler);
+ new SubscribeUSK(this, node.getClientCore(), handler);
} catch (IdentifierCollisionException e) {
handler.send(new IdentifierCollisionMessage(identifier, false));
return;
diff --git a/src/freenet/clients/fcp/TestDDARequestMessage.java b/src/freenet/clients/fcp/TestDDARequestMessage.java
index 9a1930b3db1..03c702bac3c 100644
--- a/src/freenet/clients/fcp/TestDDARequestMessage.java
+++ b/src/freenet/clients/fcp/TestDDARequestMessage.java
@@ -32,7 +32,7 @@ public TestDDARequestMessage(SimpleFieldSet fs) throws MessageInvalidException {
identifier = fs.get(DIRECTORY);
if(identifier == null)
throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "No Directory given!", null, false);
- if(identifier.length() == 0)
+ if(identifier.isEmpty())
throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "The specified Directory can't be empty!", null, false);
wantRead = fs.getBoolean(WANT_READ, false);
diff --git a/src/freenet/clients/fcp/TestDDAResponseMessage.java b/src/freenet/clients/fcp/TestDDAResponseMessage.java
index 4c999d2eb4a..b052fcf47fb 100644
--- a/src/freenet/clients/fcp/TestDDAResponseMessage.java
+++ b/src/freenet/clients/fcp/TestDDAResponseMessage.java
@@ -27,7 +27,7 @@ public TestDDAResponseMessage(SimpleFieldSet sfs) throws MessageInvalidException
identifier = sfs.get(TestDDARequestMessage.DIRECTORY);
if(identifier == null)
throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "No Directory given!", null, false);
- if(identifier.length() == 0)
+ if(identifier.isEmpty())
throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "The specified Directory can't be empty!", null, false);
readContent = sfs.get(READ_CONTENT);
diff --git a/src/freenet/clients/fcp/TextFeedMessage.java b/src/freenet/clients/fcp/TextFeedMessage.java
index a2a9908c814..ff842571af8 100644
--- a/src/freenet/clients/fcp/TextFeedMessage.java
+++ b/src/freenet/clients/fcp/TextFeedMessage.java
@@ -1,6 +1,6 @@
package freenet.clients.fcp;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
import freenet.support.api.Bucket;
import freenet.support.io.ArrayBucket;
@@ -15,13 +15,10 @@ public TextFeedMessage(String header, String shortText, String text, short prior
String messageText) {
super(header, shortText, text, priorityClass, updatedTime, sourceNodeName, composed, sent, received);
final Bucket messageTextBucket;
- try {
- if(messageText != null)
- messageTextBucket = new ArrayBucket(messageText.getBytes("UTF-8"));
- else
- messageTextBucket = new NullBucket();
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
+ if (messageText != null) {
+ messageTextBucket = new ArrayBucket(messageText.getBytes(StandardCharsets.UTF_8));
+ } else {
+ messageTextBucket = new NullBucket();
}
buckets.put("MessageText", messageTextBucket);
}
diff --git a/src/freenet/clients/fcp/URIFeedMessage.java b/src/freenet/clients/fcp/URIFeedMessage.java
index f18a7864d6e..a88b62d19d2 100644
--- a/src/freenet/clients/fcp/URIFeedMessage.java
+++ b/src/freenet/clients/fcp/URIFeedMessage.java
@@ -1,6 +1,6 @@
package freenet.clients.fcp;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
import freenet.keys.FreenetURI;
import freenet.support.SimpleFieldSet;
@@ -19,13 +19,10 @@ public URIFeedMessage(String header, String shortText, String text, short priori
super(header, shortText, text, priorityClass, updatedTime, sourceNodeName, composed, sent, received);
this.URI = URI;
final Bucket descriptionBucket;
- try {
- if(description != null)
- descriptionBucket = new ArrayBucket(description.getBytes("UTF-8"));
- else
- descriptionBucket = new NullBucket();
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
+ if (description != null) {
+ descriptionBucket = new ArrayBucket(description.getBytes(StandardCharsets.UTF_8));
+ } else {
+ descriptionBucket = new NullBucket();
}
buckets.put("Description", descriptionBucket);
}
diff --git a/src/freenet/clients/fcp/WatchFeedsMessage.java b/src/freenet/clients/fcp/WatchFeedsMessage.java
index 5d4516d3208..dfbdf5c7d8c 100644
--- a/src/freenet/clients/fcp/WatchFeedsMessage.java
+++ b/src/freenet/clients/fcp/WatchFeedsMessage.java
@@ -21,9 +21,9 @@ public String getName() {
public void run(FCPConnectionHandler handler, Node node)
throws MessageInvalidException {
if(enabled)
- node.clientCore.alerts.watch(handler);
+ node.getClientCore().getAlerts().watch(handler);
else
- node.clientCore.alerts.unwatch(handler);
+ node.getClientCore().getAlerts().unwatch(handler);
}
@Override
diff --git a/src/freenet/clients/fcp/WatchGlobal.java b/src/freenet/clients/fcp/WatchGlobal.java
index 06bb62a045d..03dffe7dff0 100644
--- a/src/freenet/clients/fcp/WatchGlobal.java
+++ b/src/freenet/clients/fcp/WatchGlobal.java
@@ -41,13 +41,13 @@ public String getName() {
@Override
public void run(final FCPConnectionHandler handler, Node node)
throws MessageInvalidException {
- if(!handler.getRebootClient().setWatchGlobal(enabled, verbosityMask, node.clientCore.getFCPServer())) {
+ if(!handler.getRebootClient().setWatchGlobal(enabled, verbosityMask, node.getClientCore().getFCPServer())) {
FCPMessage err = new ProtocolErrorMessage(ProtocolErrorMessage.PERSISTENCE_DISABLED, false, "Persistence disabled", null, true);
handler.send(err);
}
PersistentRequestClient client = handler.getForeverClient();
if(client != null)
- client.setWatchGlobal(enabled, verbosityMask, handler.server);
+ client.setWatchGlobal(enabled, verbosityMask, handler.getServer());
}
}
diff --git a/src/freenet/clients/http/BookmarkEditorToadlet.java b/src/freenet/clients/http/BookmarkEditorToadlet.java
index 65a9de77863..1092fd90642 100644
--- a/src/freenet/clients/http/BookmarkEditorToadlet.java
+++ b/src/freenet/clients/http/BookmarkEditorToadlet.java
@@ -72,7 +72,7 @@ private void addCategoryToList(BookmarkCategory cat, String path, HTMLNode list,
final String addBookmark = NodeL10n.getBase().getString("BookmarkEditorToadlet.addBookmark");
final String addCategory = NodeL10n.getBase().getString("BookmarkEditorToadlet.addCategory");
- boolean hasFriends = core.node.getDarknetConnections().length > 0;
+ boolean hasFriends = core.getNode().getDarknetConnections().length > 0;
for(int i = 0; i < items.size(); i++) {
BookmarkItem item = items.get(i);
@@ -80,7 +80,7 @@ private void addCategoryToList(BookmarkCategory cat, String path, HTMLNode list,
String itemPath = URLEncoder.encode(path + item.getName(), false);
HTMLNode li = new HTMLNode("li", "class", "item", item.getVisibleName());
String explain = item.getShortDescription();
- if(explain != null && explain.length() > 0) {
+ if(explain != null && !explain.isEmpty()) {
li.addChild("#", " (");
li.addChild("#", explain);
li.addChild("#", ")");
@@ -143,7 +143,7 @@ private void addCategoryToList(BookmarkCategory cat, String path, HTMLNode list,
}
private void sendBookmarkFeeds(HTTPRequest req, BookmarkItem item, String publicDescription) {
- for(DarknetPeerNode peer : core.node.getDarknetConnections())
+ for(DarknetPeerNode peer : core.getNode().getDarknetConnections())
if(req.isPartSet("node_" + peer.hashCode()))
peer.sendBookmarkFeed(item.getURI(), item.getName(), publicDescription, item.hasAnActivelink());
}
@@ -181,7 +181,7 @@ public void handleMethodGET(URI uri, HTTPRequest req, ToadletContext ctx)
HTMLNode pageNode = page.outer;
HTMLNode content = page.content;
String originalBookmark = req.getParam("bookmark");
- if(req.getParam("action").length() > 0 && originalBookmark.length() > 0) {
+ if(!req.getParam("action").isEmpty() && !originalBookmark.isEmpty()) {
String action = req.getParam("action");
String bookmarkPath;
try {
@@ -231,14 +231,20 @@ else if("paste".equals(action) && cutedPath != null) {
} else if("edit".equals(action) || "addItem".equals(action) || "addCat".equals(action) || "share".equals(action)) {
boolean isNew = "addItem".equals(action) || "addCat".equals(action);
String header;
- if("edit".equals(action))
- header = NodeL10n.getBase().getString("BookmarkEditorToadlet.edit" + ((bookmark instanceof BookmarkItem) ? "Bookmark" : "Category") + "Title");
- else if("addItem".equals(action))
- header = NodeL10n.getBase().getString("BookmarkEditorToadlet.addNewBookmark");
- else if("share".equals(action))
- header = NodeL10n.getBase().getString("BookmarkEditorToadlet.share");
- else
- header = NodeL10n.getBase().getString("BookmarkEditorToadlet.addNewCategory");
+ switch (action) {
+ case "edit":
+ header = NodeL10n.getBase().getString("BookmarkEditorToadlet.edit" + ((bookmark instanceof BookmarkItem) ? "Bookmark" : "Category") + "Title");
+ break;
+ case "addItem":
+ header = NodeL10n.getBase().getString("BookmarkEditorToadlet.addNewBookmark");
+ break;
+ case "share":
+ header = NodeL10n.getBase().getString("BookmarkEditorToadlet.share");
+ break;
+ default:
+ header = NodeL10n.getBase().getString("BookmarkEditorToadlet.addNewCategory");
+ break;
+ }
HTMLNode actionBoxContent = pageMaker.getInfobox("infobox-query", header, content, "bookmark-action", false);
@@ -269,21 +275,21 @@ else if("share".equals(action))
form.addChild("input", new String[]{"type", "id", "name", "checked"}, new String[]{"checkbox", "hasAnActivelink", "hasAnActivelink", String.valueOf(item.hasAnActivelink())});
else
form.addChild("input", new String[]{"type", "id", "name"}, new String[]{"checkbox", "hasAnActivelink", "hasAnActivelink"});
- if(core.node.getDarknetConnections().length > 0 && ("addItem".equals(action) || "share".equals(action))) {
+ if(core.getNode().getDarknetConnections().length > 0 && ("addItem".equals(action) || "share".equals(action))) {
form.addChild("br");
form.addChild("br");
- if (core.node.isFProxyJavascriptEnabled()) {
+ if (core.getNode().isFProxyJavascriptEnabled()) {
form.addChild("script", new String[] {"type", "src"}, new String[] {"text/javascript", "/static/js/checkall.js"});
}
HTMLNode peerTable = form.addChild("table", "class", "darknet_connections");
- if (core.node.isFProxyJavascriptEnabled()) {
+ if (core.getNode().isFProxyJavascriptEnabled()) {
HTMLNode headerRow = peerTable.addChild("tr");
headerRow.addChild("th").addChild("input", new String[] { "type", "onclick" }, new String[] { "checkbox", "checkAll(this, 'darknet_connections')" });
headerRow.addChild("th", NodeL10n.getBase().getString("QueueToadlet.recommendToFriends"));
} else {
peerTable.addChild("tr").addChild("th", "colspan", "2", NodeL10n.getBase().getString("QueueToadlet.recommendToFriends"));
}
- for(DarknetPeerNode peer : core.node.getDarknetConnections()) {
+ for(DarknetPeerNode peer : core.getNode().getDarknetConnections()) {
HTMLNode peerRow = peerTable.addChild("tr", "class", "darknet_connections_normal");
peerRow.addChild("td", "class", "peer-marker").addChild("input", new String[] { "type", "name" }, new String[] { "checkbox", "node_" + peer.hashCode() });
peerRow.addChild("td", "class", "peer-name").addChild("#", peer.getName());
@@ -373,7 +379,10 @@ else if("edit".equals(action) || "addItem".equals(action) || "addCat".equals(act
if(req.isPartSet("name"))
name = req.getPartAsStringFailsafe("name", MAX_NAME_LENGTH);
- if("edit".equals(action)) {
+ Bookmark targetBookmark = bookmarkManager.getBookmarkByPath(bookmarkManager.parentPath(bookmarkPath) + name);
+ if (!isValidName(name) || (targetBookmark != null && targetBookmark != bookmark)) {
+ addNameError(pageMaker, content);
+ } else if ("edit".equals(action)) {
bookmarkManager.renameBookmark(bookmarkPath, name);
boolean hasAnActivelink = req.isPartSet("hasAnActivelink");
if(bookmark instanceof BookmarkItem) {
@@ -388,7 +397,7 @@ else if("edit".equals(action) || "addItem".equals(action) || "addCat".equals(act
} else if("addItem".equals(action) || "addCat".equals(action)) {
- Bookmark newBookmark = null;
+ Bookmark newBookmark;
if("addItem".equals(action)) {
FreenetURI key = new FreenetURI(req.getPartAsStringFailsafe("key", MAX_KEY_LENGTH));
/* TODO:
@@ -398,29 +407,21 @@ else if("edit".equals(action) || "addItem".equals(action) || "addCat".equals(act
* - values as "on", "true", "yes" should be accepted.
*/
boolean hasAnActivelink = req.isPartSet("hasAnActivelink");
- if (!isValidName(name)) {
- addNameError(pageMaker, content);
- } else
- newBookmark = new BookmarkItem(key, name,
- req.getPartAsStringFailsafe("descB", MAX_KEY_LENGTH),
- req.getPartAsStringFailsafe("explain", MAX_EXPLANATION_LENGTH),
- hasAnActivelink, bookmarkManager, ctx.getAlertManager());
- } else
- if (!isValidName(name)) {
- addNameError(pageMaker, content);
- } else
- newBookmark = new BookmarkCategory(name);
-
- if (newBookmark != null) {
-
- bookmarkManager.addBookmark(bookmarkPath, newBookmark);
- bookmarkManager.storeBookmarks();
- if(newBookmark instanceof BookmarkItem)
- sendBookmarkFeeds(req, (BookmarkItem) newBookmark, req.getPartAsStringFailsafe("publicDescB", MAX_KEY_LENGTH));
-
- pageMaker.getInfobox("infobox-success", NodeL10n.getBase().getString("BookmarkEditorToadlet.addedNewBookmarkTitle"), content, "bookmark-add-new", false).
- addChild("p", NodeL10n.getBase().getString("BookmarkEditorToadlet.addedNewBookmark"));
+ newBookmark = new BookmarkItem(key, name,
+ req.getPartAsStringFailsafe("descB", MAX_KEY_LENGTH),
+ req.getPartAsStringFailsafe("explain", MAX_EXPLANATION_LENGTH),
+ hasAnActivelink, bookmarkManager, ctx.getAlertManager());
+ } else {
+ newBookmark = new BookmarkCategory(name);
}
+
+ bookmarkManager.addBookmark(bookmarkPath, newBookmark);
+ bookmarkManager.storeBookmarks();
+ if(newBookmark instanceof BookmarkItem)
+ sendBookmarkFeeds(req, (BookmarkItem) newBookmark, req.getPartAsStringFailsafe("publicDescB", MAX_KEY_LENGTH));
+
+ pageMaker.getInfobox("infobox-success", NodeL10n.getBase().getString("BookmarkEditorToadlet.addedNewBookmarkTitle"), content, "bookmark-add-new", false).
+ addChild("p", NodeL10n.getBase().getString("BookmarkEditorToadlet.addedNewBookmark"));
}
}
else if("share".equals(action))
diff --git a/src/freenet/clients/http/ConfigToadlet.java b/src/freenet/clients/http/ConfigToadlet.java
index 2086e0a8a82..e2e670d3379 100644
--- a/src/freenet/clients/http/ConfigToadlet.java
+++ b/src/freenet/clients/http/ConfigToadlet.java
@@ -597,7 +597,7 @@ public void handleMethodGET(URI uri, HTTPRequest req, ToadletContext ctx)
break;
case BOOLEAN:
configItemValueNode.addChild(addBooleanComboBox(
- Boolean.valueOf(value), fullName,
+ Boolean.parseBoolean(value), fullName,
callback.isReadOnly()));
break;
case DIRECTORY:
diff --git a/src/freenet/clients/http/ConnectionsToadlet.java b/src/freenet/clients/http/ConnectionsToadlet.java
index e9bf29b640b..85a3850e98c 100644
--- a/src/freenet/clients/http/ConnectionsToadlet.java
+++ b/src/freenet/clients/http/ConnectionsToadlet.java
@@ -4,7 +4,6 @@
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
-import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
@@ -12,7 +11,13 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.text.DecimalFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import freenet.client.FetchException;
import freenet.client.HighLevelSimpleClient;
@@ -28,8 +33,8 @@
import freenet.keys.FreenetURI;
import freenet.l10n.NodeL10n;
import freenet.node.DarknetPeerNode;
-import freenet.node.DarknetPeerNode.FRIEND_VISIBILITY;
import freenet.node.DarknetPeerNode.FRIEND_TRUST;
+import freenet.node.DarknetPeerNode.FRIEND_VISIBILITY;
import freenet.node.FSParseException;
import freenet.node.Node;
import freenet.node.NodeClientCore;
@@ -112,39 +117,43 @@ private int compareInts(int int1, int int2) {
}
protected int customCompare(PeerNodeStatus firstNode, PeerNodeStatus secondNode, String sortBy2) {
- if(sortBy.equals("address")){
+ switch (sortBy) {
+ case "address":
return firstNode.getPeerAddress().compareToIgnoreCase(secondNode.getPeerAddress());
- }else if(sortBy.equals("location")){
+ case "location":
return compareLocations(firstNode, secondNode);
- }else if(sortBy.equals("version")){
+ case "version":
return Version.getArbitraryBuildNumber(firstNode.getVersion(), -1) - Version.getArbitraryBuildNumber(secondNode.getVersion(), -1);
- }else if(sortBy.equals("backoffRT")){
+ case "backoffRT":
return Double.compare(firstNode.getBackedOffPercent(true), secondNode.getBackedOffPercent(true));
- }else if(sortBy.equals("backoffBulk")){
+ case "backoffBulk":
return Double.compare(firstNode.getBackedOffPercent(false), secondNode.getBackedOffPercent(false));
- }else if(sortBy.equals(("overload_p"))){
+ case "overload_p":
return Double.compare(firstNode.getPReject(), secondNode.getPReject());
- }else if(sortBy.equals(("idle"))){
+ case "idle":
return compareLongs(firstNode.getTimeLastConnectionCompleted(), secondNode.getTimeLastConnectionCompleted());
- }else if(sortBy.equals("time_routable")){
+ case "time_routable":
return Double.compare(firstNode.getPercentTimeRoutableConnection(), secondNode.getPercentTimeRoutableConnection());
- }else if(sortBy.equals("total_traffic")){
- long total1 = firstNode.getTotalInputBytes()+firstNode.getTotalOutputBytes();
- long total2 = secondNode.getTotalInputBytes()+secondNode.getTotalOutputBytes();
+ case "total_traffic": {
+ long total1 = firstNode.getTotalInputBytes() + firstNode.getTotalOutputBytes();
+ long total2 = secondNode.getTotalInputBytes() + secondNode.getTotalOutputBytes();
return compareLongs(total1, total2);
- }else if(sortBy.equals("total_traffic_since_startup")){
- long total1 = firstNode.getTotalInputSinceStartup()+firstNode.getTotalOutputSinceStartup();
- long total2 = secondNode.getTotalInputSinceStartup()+secondNode.getTotalOutputSinceStartup();
+ }
+ case "total_traffic_since_startup": {
+ long total1 = firstNode.getTotalInputSinceStartup() + firstNode.getTotalOutputSinceStartup();
+ long total2 = secondNode.getTotalInputSinceStartup() + secondNode.getTotalOutputSinceStartup();
return compareLongs(total1, total2);
- }else if(sortBy.equals("selection_percentage")){
+ }
+ case "selection_percentage":
return Double.compare(firstNode.getSelectionRate(), secondNode.getSelectionRate());
- }else if(sortBy.equals("time_delta")){
+ case "time_delta":
return compareLongs(firstNode.getClockDelta(), secondNode.getClockDelta());
- }else if(sortBy.equals(("uptime"))){
+ case "uptime":
return compareInts(firstNode.getReportedUptimePercentage(), secondNode.getReportedUptimePercentage());
- }else
+ default:
return 0;
}
+ }
private int compareLocations(PeerNodeStatus firstNode, PeerNodeStatus secondNode) {
double diff = firstNode.getLocation() - secondNode.getLocation(); // Can occasionally be the same, and we must have a consistent sort order
@@ -171,8 +180,8 @@ protected ConnectionsToadlet(Node n, NodeClientCore core, HighLevelSimpleClient
super(client);
this.node = n;
this.core = core;
- this.stats = n.nodeStats;
- this.peers = n.peers;
+ this.stats = n.getNodeStats();
+ this.peers = n.getPeers();
REF_LINK = HTMLNode.link(path()+"myref.fref").setReadOnly();
REFTEXT_LINK = HTMLNode.link(path()+"myref.txt").setReadOnly();
}
@@ -258,7 +267,7 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
if(advancedMode) {
/* node status values */
- long nodeUptimeSeconds = SECONDS.convert(now - node.startupTime, MILLISECONDS);
+ long nodeUptimeSeconds = SECONDS.convert(now - node.getStartupTime(), MILLISECONDS);
int bwlimitDelayTime = (int) stats.getBwlimitDelayTime();
int nodeAveragePingTime = (int) stats.getNodeAveragePingTime();
int networkSizeEstimateSession = stats.getDarknetSizeEstimate(-1);
@@ -467,7 +476,7 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
double totalSelectionRate = 0.0;
//calculate the total selection rate using all peers, not just the peers for the current mode,
- PeerNodeStatus[] allPeerNodeStatuses = node.peers.getPeerNodeStatuses(true);
+ PeerNodeStatus[] allPeerNodeStatuses = node.getPeers().getPeerNodeStatuses(true);
for(PeerNodeStatus status : allPeerNodeStatuses) {
totalSelectionRate += status.getSelectionRate();
}
@@ -498,7 +507,7 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
//i now points to the proper location (equal, insertion point, or end-of-list)
//maybe better called "reverseGroup"?
List peerGroup;
- if (i();
@@ -562,7 +571,7 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
foafRow.addChild("td", String.valueOf(peersWithFriend.size()));
HTMLNode locationCell=foafRow.addChild("td", "class", "peer-location");
for (PeerNodeStatus peerNodeStatus : peersWithFriend) {
- String address=((peerNodeStatus.getPeerAddress() != null) ? (peerNodeStatus.getPeerAddress() + ':' + peerNodeStatus.getPeerPort()) : (l10n("unknownAddress")));
+ String address=((peerNodeStatus.getPeerAddress() != null) ? peerNodeStatus.getPeerAddressAndPort() : (l10n("unknownAddress")));
locationCell.addChild("i", address);
locationCell.addChild("br");
}
@@ -587,7 +596,7 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
// our reference
if(shouldDrawNoderefBox(advancedMode)) {
drawAddPeerBox(contentNode, ctx);
- drawNoderefBox(contentNode, getNoderef(), true);
+ drawNoderefBox(contentNode, getNoderef());
}
this.writeHTMLReply(ctx, 200, "OK", pageNode.generate());
@@ -625,7 +634,7 @@ public void handleMethodPOST(URI uri, final HTTPRequest request, ToadletContext
privateComment = request.getPartAsStringFailsafe("peerPrivateNote", 250).trim();
if (Boolean.parseBoolean(request.getPartAsStringFailsafe("peers-offers-files", 5))) {
- File[] files = core.node.runDir().file("peers-offers").listFiles();
+ File[] files = core.getNode().runDir().file("peers-offers").listFiles();
if (files != null && files.length > 0) {
StringBuilder peersOffersFilesContent = new StringBuilder();
for (final File file : files) {
@@ -638,17 +647,17 @@ public void handleMethodPOST(URI uri, final HTTPRequest request, ToadletContext
reftext = peersOffersFilesContent.toString();
}
- node.config.get("node").set("peersOffersDismissed", true);
+ node.getConfig().get("node").set("peersOffersDismissed", true);
}
String trustS = request.getPartAsStringFailsafe("trust", 10);
FRIEND_TRUST trust = null;
- if(trustS != null && !trustS.equals(""))
+ if(trustS != null && !trustS.isEmpty())
trust = FRIEND_TRUST.valueOf(trustS);
String visibilityS = request.getPartAsStringFailsafe("visibility", 10);
FRIEND_VISIBILITY visibility = null;
- if(visibilityS != null && !visibilityS.equals(""))
+ if(visibilityS != null && !visibilityS.isEmpty())
visibility = FRIEND_VISIBILITY.valueOf(visibilityS);
if(trust == null && !isOpennet()) {
@@ -664,7 +673,7 @@ public void handleMethodPOST(URI uri, final HTTPRequest request, ToadletContext
}
StringBuilder ref;
- if (urltext.length() > 0) {
+ if (!urltext.isEmpty()) {
// fetch reference from a URL
try {
FreenetURI refUri = new FreenetURI(urltext);
@@ -677,7 +686,7 @@ public void handleMethodPOST(URI uri, final HTTPRequest request, ToadletContext
this.sendErrorPage(ctx, 200, l10n("failedToAddNodeTitle"), NodeL10n.getBase().getString("DarknetConnectionsToadlet.cantFetchNoderefURL", new String[]{"url"}, new String[]{urltext}), !isOpennet());
return;
}
- } else if (reftext.length() > 0) {
+ } else if (!reftext.isEmpty()) {
// read from post data or file upload
// this slightly scary looking regexp chops any extra characters off the beginning or ends of lines and removes extra line breaks
ref = new StringBuilder(reftext.replaceAll(".*?((?:[\\w,\\.]+\\=[^\r\n]+?)|(?:End))[ \\t]*(?:\\r?\\n)+", "$1\n"));
@@ -727,7 +736,7 @@ public void handleMethodPOST(URI uri, final HTTPRequest request, ToadletContext
PeerAdditionReturnCodes result=addNewNode(nodesToAdd[i].trim().concat("\nEnd"), privateComment, trust, visibility);
//Store the result
Integer prev = results.get(result);
- if(prev == null) prev = Integer.valueOf(0);
+ if(prev == null) prev = 0;
results.put(result, prev+1);
}
@@ -857,13 +866,10 @@ protected void handleAltPost(URI uri, HTTPRequest request, ToadletContext ctx, b
final HTMLNode REFTEXT_LINK;
/**
- *
* @param contentNode Node to add noderef box to.
* @param fs Noderef to render as text if requested.
- * @param showNoderef If true, render the text of the noderef so that it may be copy-pasted. If false, only
- * show a link to download it.
*/
- void drawNoderefBox(HTMLNode contentNode, SimpleFieldSet fs, boolean showNoderef) {
+ void drawNoderefBox(HTMLNode contentNode, SimpleFieldSet fs) {
HTMLNode referenceInfobox = contentNode.addChild("div", "class", "infobox infobox-normal");
HTMLNode headerReferenceInfobox = referenceInfobox.addChild("div", "class", "infobox-header");
// FIXME better way to deal with this sort of thing???
@@ -882,13 +888,17 @@ void drawNoderefBox(HTMLNode contentNode, SimpleFieldSet fs, boolean showNoderef
myName.addChild("span", "]");
}
- if (showNoderef) {
HTMLNode warningSentence = referenceInfoboxContent.addChild("p");
NodeL10n.getBase().addL10nSubstitution(warningSentence, "DarknetConnectionsToadlet.referenceCopyWarning",
new String[] { "bold" },
new HTMLNode[] { HTMLNode.STRONG });
referenceInfoboxContent.addChild("pre", "id", "reference", fs.toOrderedStringWithBase64() + '\n');
+
+ if(!isOpennet()) {
+ HTMLNode myIps = referenceInfoboxContent.addChild("p");
+ myIps.addChild("span", NodeL10n.getBase().getString("DarknetConnectionsToadlet.myIps", "ips", fs.get("physical.udp")));
}
+
}
protected abstract String getPageTitle(String titleCountString);
@@ -982,7 +992,7 @@ private void drawRow(HTMLNode peerTable, PeerNodeStatus peerNodeStatus, boolean
country.renderFlagIcon(addressRow);
}
- addressRow.addChild("#", ((peerNodeStatus.getPeerAddress() != null) ? (peerNodeStatus.getPeerAddress() + ':' + peerNodeStatus.getPeerPort()) : (l10n("unknownAddress"))) + pingTime);
+ addressRow.addChild("#", ((peerNodeStatus.getPeerAddress() != null) ? peerNodeStatus.getPeerAddressAndPort() : (l10n("unknownAddress"))) + pingTime);
// version column
if (peerNodeStatus.getStatusValue() != PeerManager.PEER_NODE_STATUS_NEVER_CONNECTED && (peerNodeStatus.isPublicInvalidVersion() || peerNodeStatus.isPublicReverseInvalidVersion())) { // Don't draw attention to a version problem if NEVER CONNECTED
@@ -1143,7 +1153,7 @@ private void drawMessageTypes(HTMLNode peerTable, PeerNodeStatus peerNodeStatus)
String messageName = entry.getKey();
Long messageCount = entry.getValue();
messageNames.add(messageName);
- messageCounts.put(messageName, new Long[] { messageCount, Long.valueOf(0) });
+ messageCounts.put(messageName, new Long[] { messageCount, 0L});
}
for (Map.Entry entry : peerNodeStatus.getLocalMessagesSent().entrySet() ) {
String messageName = entry.getKey();
@@ -1153,7 +1163,7 @@ private void drawMessageTypes(HTMLNode peerTable, PeerNodeStatus peerNodeStatus)
}
Long[] existingCounts = messageCounts.get(messageName);
if (existingCounts == null) {
- messageCounts.put(messageName, new Long[] { Long.valueOf(0), messageCount });
+ messageCounts.put(messageName, new Long[] {0L, messageCount });
} else {
existingCounts[1] = messageCount;
}
diff --git a/src/freenet/clients/http/ConnectivityToadlet.java b/src/freenet/clients/http/ConnectivityToadlet.java
index 1ede00d40f6..28b04f31e8c 100644
--- a/src/freenet/clients/http/ConnectivityToadlet.java
+++ b/src/freenet/clients/http/ConnectivityToadlet.java
@@ -65,9 +65,9 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
portInfobox.addChild("div", "class", "infobox-header", l10nConn("nodePortsTitle"));
HTMLNode portInfoboxContent = portInfobox.addChild("div", "class", "infobox-content");
HTMLNode portInfoList = portInfoboxContent.addChild("ul");
- SimpleFieldSet fproxyConfig = node.config.get("fproxy").exportFieldSet(true);
- SimpleFieldSet fcpConfig = node.config.get("fcp").exportFieldSet(true);
- SimpleFieldSet tmciConfig = node.config.get("console").exportFieldSet(true);
+ SimpleFieldSet fproxyConfig = node.getConfig().get("fproxy").exportFieldSet(true);
+ SimpleFieldSet fcpConfig = node.getConfig().get("fcp").exportFieldSet(true);
+ SimpleFieldSet tmciConfig = node.getConfig().get("console").exportFieldSet(true);
portInfoList.addChild("li", NodeL10n.getBase().getString("DarknetConnectionsToadlet.darknetFnpPort", new String[] { "port" }, new String[] { Integer.toString(node.getFNPPort()) }));
int opennetPort = node.getOpennetFNPPort();
if(opennetPort > 0)
@@ -94,7 +94,7 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
// Add connection type box.
- node.ipDetector.addConnectionTypeBox(contentNode);
+ node.getIpDetector().addConnectionTypeBox(contentNode);
UdpSocketHandler[] handlers = node.getPacketSocketHandlers();
diff --git a/src/freenet/clients/http/ContentFilterToadlet.java b/src/freenet/clients/http/ContentFilterToadlet.java
index aee3577c242..d240f02c563 100644
--- a/src/freenet/clients/http/ContentFilterToadlet.java
+++ b/src/freenet/clients/http/ContentFilterToadlet.java
@@ -215,7 +215,7 @@ private void handleFilterRequest(HTTPRequest request, ToadletContext ctx, NodeCl
Bucket bucket;
if (localFile) {
filename = request.getPartAsStringFailsafe("filename", QueueToadlet.MAX_FILENAME_LENGTH);
- if (mimeType.length() == 0) {
+ if (mimeType.isEmpty()) {
mimeType = DefaultMIMETypes.guessMIMEType(filename, false);
}
File file = new File(filename);
@@ -226,12 +226,12 @@ private void handleFilterRequest(HTTPRequest request, ToadletContext ctx, NodeCl
throw new BadRequestException("filename");
}
filename = file.getFilename();
- if (mimeType.length() == 0) {
+ if (mimeType.isEmpty()) {
mimeType = file.getContentType();
}
bucket = file.getData();
}
- if (filename.length() == 0) {
+ if (filename.isEmpty()) {
throw new BadRequestException("filename");
}
String resultFilename = makeResultFilename(filename, mimeType);
diff --git a/src/freenet/clients/http/Cookie.java b/src/freenet/clients/http/Cookie.java
index 02c25d22c85..f167971295c 100644
--- a/src/freenet/clients/http/Cookie.java
+++ b/src/freenet/clients/http/Cookie.java
@@ -5,12 +5,10 @@
import java.net.URI;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
-import freenet.support.CurrentTimeUTC;
import freenet.support.TimeUtil;
/**
@@ -37,8 +35,6 @@ public class Cookie {
public static final HashSet httpSeparatorCharacters =
new HashSet(Arrays.asList(new Character[] { '(', ')', '<', '>', '@', ',', ';', ':', '\\', '\"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t' }));
- private static final Charset usasciiCharset = Charset.forName("US-ASCII");
-
protected int version;
@@ -271,7 +267,7 @@ The following grammar uses the notation, and tokens DIGIT (decimal d
}
public static Date validateExpirationDate(Date expirationDate) {
- if(CurrentTimeUTC.get().after(expirationDate))
+ if(new Date().after(expirationDate))
throw new IllegalArgumentException("Illegal expiration date, is in past: " + expirationDate);
return expirationDate;
diff --git a/src/freenet/clients/http/DarknetAddRefToadlet.java b/src/freenet/clients/http/DarknetAddRefToadlet.java
index 9c4b865becd..a30ca12537d 100644
--- a/src/freenet/clients/http/DarknetAddRefToadlet.java
+++ b/src/freenet/clients/http/DarknetAddRefToadlet.java
@@ -30,7 +30,7 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
String path = uri.getPath();
if(path.endsWith(NodeFile.InstallerWindows.getFilename())) {
- File installer = node.nodeUpdater.getInstallerWindows();
+ File installer = node.getNodeUpdater().getInstallerWindows();
if(installer != null) {
FileBucket bucket = new FileBucket(installer, true, false, false, false);
this.writeReply(ctx, 200, "application/x-msdownload", "OK", bucket);
@@ -39,7 +39,7 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
}
if(path.endsWith(NodeFile.InstallerNonWindows.getFilename())) {
- File installer = node.nodeUpdater.getInstallerNonWindows();
+ File installer = node.getNodeUpdater().getInstallerNonWindows();
if(installer != null) {
FileBucket bucket = new FileBucket(installer, true, false, false, false);
this.writeReply(ctx, 200, "application/x-java-archive", "OK", bucket);
@@ -59,7 +59,7 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
boxContent.addChild("p", l10n("explainBox1"));
boxContent.addChild("p", l10n("explainBox2"));
- File installer = node.nodeUpdater.getInstallerWindows();
+ File installer = node.getNodeUpdater().getInstallerWindows();
String shortFilename = NodeFile.InstallerWindows.getFilename();
HTMLNode p = boxContent.addChild("p");
@@ -68,9 +68,9 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
NodeL10n.getBase().addL10nSubstitution(p, "DarknetAddRefToadlet.explainInstallerWindows", new String[] { "filename", "get-windows" },
new HTMLNode[] { HTMLNode.text(installer.getCanonicalPath()), HTMLNode.link(path()+shortFilename) });
else
- NodeL10n.getBase().addL10nSubstitution(p, "DarknetAddRefToadlet.explainInstallerWindowsNotYet", new String[] { "link" }, new HTMLNode[] { HTMLNode.link("/"+node.nodeUpdater.getInstallerWindowsURI().toString()) });
+ NodeL10n.getBase().addL10nSubstitution(p, "DarknetAddRefToadlet.explainInstallerWindowsNotYet", new String[] { "link" }, new HTMLNode[] { HTMLNode.link("/"+node.getNodeUpdater().getInstallerWindowsURI().toString()) });
- installer = node.nodeUpdater.getInstallerNonWindows();
+ installer = node.getNodeUpdater().getInstallerNonWindows();
shortFilename = NodeFile.InstallerNonWindows.getFilename();
boxContent.addChild("#", " ");
@@ -81,12 +81,12 @@ public void handleMethodGET(URI uri, final HTTPRequest request, ToadletContext c
NodeL10n.getBase().addL10nSubstitution(p, "DarknetAddRefToadlet.explainInstallerNonWindows", new String[] { "filename", "get-nonwindows", "shortfilename" },
new HTMLNode[] { HTMLNode.text(installer.getCanonicalPath()), HTMLNode.link(path()+shortFilename), HTMLNode.text(shortFilename) });
else
- NodeL10n.getBase().addL10nSubstitution(p, "DarknetAddRefToadlet.explainInstallerNonWindowsNotYet", new String[] { "link", "shortfilename" }, new HTMLNode[] { HTMLNode.link("/"+node.nodeUpdater.getInstallerNonWindowsURI().toString()), HTMLNode.text(shortFilename) });
+ NodeL10n.getBase().addL10nSubstitution(p, "DarknetAddRefToadlet.explainInstallerNonWindowsNotYet", new String[] { "link", "shortfilename" }, new HTMLNode[] { HTMLNode.link("/"+node.getNodeUpdater().getInstallerNonWindowsURI().toString()), HTMLNode.text(shortFilename) });
ConnectionsToadlet.drawAddPeerBox(contentNode, ctx, false, friendsToadlet.path());
- friendsToadlet.drawNoderefBox(contentNode, getNoderef(), pageMaker.advancedMode(request, this.container));
+ friendsToadlet.drawNoderefBox(contentNode, getNoderef());
this.writeHTMLReply(ctx, 200, "OK", pageNode.generate());
}
diff --git a/src/freenet/clients/http/DarknetConnectionsToadlet.java b/src/freenet/clients/http/DarknetConnectionsToadlet.java
index 03a8c5b1311..4680753ced7 100644
--- a/src/freenet/clients/http/DarknetConnectionsToadlet.java
+++ b/src/freenet/clients/http/DarknetConnectionsToadlet.java
@@ -41,18 +41,20 @@ protected class DarknetComparator extends ComparatorByStatus {
@Override
protected int customCompare(PeerNodeStatus firstNode, PeerNodeStatus secondNode, String sortBy) {
- if(sortBy.equals("name")) {
- return ((DarknetPeerNodeStatus)firstNode).getName().compareToIgnoreCase(((DarknetPeerNodeStatus)secondNode).getName());
- }else if(sortBy.equals("privnote")){
- return ((DarknetPeerNodeStatus)firstNode).getPrivateDarknetCommentNote().compareToIgnoreCase(((DarknetPeerNodeStatus)secondNode).getPrivateDarknetCommentNote());
- } else if(sortBy.equals("trust")){
- return ((DarknetPeerNodeStatus)firstNode).getTrustLevel().compareTo(((DarknetPeerNodeStatus)secondNode).getTrustLevel());
- } else if(sortBy.equals("visibility")){
- int ret = ((DarknetPeerNodeStatus)firstNode).getOurVisibility().compareTo(((DarknetPeerNodeStatus)secondNode).getOurVisibility());
- if(ret != 0) return ret;
- return ((DarknetPeerNodeStatus)firstNode).getTheirVisibility().compareTo(((DarknetPeerNodeStatus)secondNode).getTheirVisibility());
- } else
- return super.customCompare(firstNode, secondNode, sortBy);
+ switch (sortBy) {
+ case "name":
+ return ((DarknetPeerNodeStatus) firstNode).getName().compareToIgnoreCase(((DarknetPeerNodeStatus) secondNode).getName());
+ case "privnote":
+ return ((DarknetPeerNodeStatus) firstNode).getPrivateDarknetCommentNote().compareToIgnoreCase(((DarknetPeerNodeStatus) secondNode).getPrivateDarknetCommentNote());
+ case "trust":
+ return ((DarknetPeerNodeStatus) firstNode).getTrustLevel().compareTo(((DarknetPeerNodeStatus) secondNode).getTrustLevel());
+ case "visibility":
+ int ret = ((DarknetPeerNodeStatus) firstNode).getOurVisibility().compareTo(((DarknetPeerNodeStatus) secondNode).getOurVisibility());
+ if (ret != 0) return ret;
+ return ((DarknetPeerNodeStatus) firstNode).getTheirVisibility().compareTo(((DarknetPeerNodeStatus) secondNode).getTheirVisibility());
+ default:
+ return super.customCompare(firstNode, secondNode, sortBy);
+ }
}
/** Default comparison, after taking into account status */
@@ -131,7 +133,7 @@ protected SimpleFieldSet getNoderef() {
@Override
protected PeerNodeStatus[] getPeerNodeStatuses(boolean noHeavy) {
- return node.peers.getDarknetPeerNodeStatuses(noHeavy);
+ return node.getPeers().getDarknetPeerNodeStatuses(noHeavy);
}
@Override
diff --git a/src/freenet/clients/http/DiagnosticToadlet.java b/src/freenet/clients/http/DiagnosticToadlet.java
index a44a33d54bb..3bdf30e062d 100644
--- a/src/freenet/clients/http/DiagnosticToadlet.java
+++ b/src/freenet/clients/http/DiagnosticToadlet.java
@@ -69,8 +69,8 @@ protected DiagnosticToadlet(Node n, NodeClientCore core, FCPServer fcp, HighLeve
this.node = n;
this.core = core;
this.fcp = fcp;
- stats = node.nodeStats;
- peers = node.peers;
+ stats = node.getNodeStats();
+ peers = node.getPeers();
/* copied from NodeL10n constructor. */
baseL10n = new BaseL10n("freenet/l10n/", "freenet.l10n.${lang}.properties", new File(".").getPath()+File.separator+"freenet.l10n.${lang}.override.properties", BaseL10n.LANGUAGE.ENGLISH);
}
@@ -79,9 +79,9 @@ public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx) th
if(!ctx.checkFullAccess(this))
return;
- node.clientCore.bandwidthStatsPutter.updateData(node);
+ node.getClientCore().getBandwidthStatsPutter().updateData(node);
- final SubConfig nodeConfig = node.config.get("node");
+ final SubConfig nodeConfig = node.getConfig().get("node");
StringBuilder textBuilder = new StringBuilder();
@@ -160,7 +160,7 @@ public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx) th
// drawActivity
textBuilder.append("Activity:\n");
- RequestTracker tracker = node.tracker;
+ RequestTracker tracker = node.getTracker();
int numLocalCHKInserts = tracker.getNumLocalCHKInserts();
int numRemoteCHKInserts = tracker.getNumRemoteCHKInserts();
int numLocalSSKInserts = tracker.getNumLocalSSKInserts();
@@ -285,23 +285,23 @@ public int compare(PeerNodeStatus firstNode, PeerNodeStatus secondNode) {
// drawBandwidth
textBuilder.append("Bandwidth:\n");
- long[] total = node.collector.getTotalIO();
+ long[] total = node.getCollector().getTotalIO();
if(total[0] == 0 || total[1] == 0)
textBuilder.append("bandwidth error\n");
else {
final long now = System.currentTimeMillis();
- final long nodeUptimeSeconds = (now - node.startupTime) / 1000;
+ final long nodeUptimeSeconds = (now - node.getStartupTime()) / 1000;
long total_output_rate = (total[0]) / nodeUptimeSeconds;
long total_input_rate = (total[1]) / nodeUptimeSeconds;
long totalPayload = node.getTotalPayloadSent();
long total_payload_rate = totalPayload / nodeUptimeSeconds;
- if(node.clientCore == null) throw new NullPointerException();
- BandwidthStatsContainer stats = node.clientCore.bandwidthStatsPutter.getLatestBWData();
+ if(node.getClientCore() == null) throw new NullPointerException();
+ BandwidthStatsContainer stats = node.getClientCore().getBandwidthStatsPutter().getLatestBWData();
if(stats == null) throw new NullPointerException();
long overall_total_out = stats.totalBytesOut;
long overall_total_in = stats.totalBytesIn;
int percent = (int) (100 * totalPayload / total[0]);
- long[] rate = node.nodeStats.getNodeIOStats();
+ long[] rate = node.getNodeStats().getNodeIOStats();
long delta = (rate[5] - rate[2]) / 1000;
if(delta > 0) {
long output_rate = (rate[3] - rate[0]) / delta;
@@ -319,30 +319,30 @@ public int compare(PeerNodeStatus firstNode, PeerNodeStatus secondNode) {
textBuilder.append(l10n("payloadOutput", new String[] { "total", "rate", "percent" }, new String[] { SizeUtil.formatSize(totalPayload, true), SizeUtil.formatSize(total_payload_rate, true), Integer.toString(percent) } )).append("\n");
textBuilder.append(l10n("totalInput", new String[] { "total" }, new String[] { SizeUtil.formatSize(overall_total_in, true) })).append("\n");
textBuilder.append(l10n("totalOutput", new String[] { "total" }, new String[] { SizeUtil.formatSize(overall_total_out, true) } )).append("\n");
- long totalBytesSentCHKRequests = node.nodeStats.getCHKRequestTotalBytesSent();
- long totalBytesSentSSKRequests = node.nodeStats.getSSKRequestTotalBytesSent();
- long totalBytesSentCHKInserts = node.nodeStats.getCHKInsertTotalBytesSent();
- long totalBytesSentSSKInserts = node.nodeStats.getSSKInsertTotalBytesSent();
- long totalBytesSentOfferedKeys = node.nodeStats.getOfferedKeysTotalBytesSent();
- long totalBytesSendOffers = node.nodeStats.getOffersSentBytesSent();
- long totalBytesSentSwapOutput = node.nodeStats.getSwappingTotalBytesSent();
- long totalBytesSentAuth = node.nodeStats.getTotalAuthBytesSent();
- long totalBytesSentAckOnly = node.nodeStats.getNotificationOnlyPacketsSentBytes();
- long totalBytesSentResends = node.nodeStats.getResendBytesSent();
- long totalBytesSentUOM = node.nodeStats.getUOMBytesSent();
- long totalBytesSentAnnounce = node.nodeStats.getAnnounceBytesSent();
- long totalBytesSentAnnouncePayload = node.nodeStats.getAnnounceBytesPayloadSent();
- long totalBytesSentRoutingStatus = node.nodeStats.getRoutingStatusBytes();
- long totalBytesSentNetworkColoring = node.nodeStats.getNetworkColoringSentBytes();
- long totalBytesSentPing = node.nodeStats.getPingSentBytes();
- long totalBytesSentProbeRequest = node.nodeStats.getProbeRequestSentBytes();
- long totalBytesSentRouted = node.nodeStats.getRoutedMessageSentBytes();
- long totalBytesSentDisconn = node.nodeStats.getDisconnBytesSent();
- long totalBytesSentInitial = node.nodeStats.getInitialMessagesBytesSent();
- long totalBytesSentChangedIP = node.nodeStats.getChangedIPBytesSent();
- long totalBytesSentNodeToNode = node.nodeStats.getNodeToNodeBytesSent();
- long totalBytesSentAllocationNotices = node.nodeStats.getAllocationNoticesBytesSent();
- long totalBytesSentFOAF = node.nodeStats.getFOAFBytesSent();
+ long totalBytesSentCHKRequests = node.getNodeStats().getCHKRequestTotalBytesSent();
+ long totalBytesSentSSKRequests = node.getNodeStats().getSSKRequestTotalBytesSent();
+ long totalBytesSentCHKInserts = node.getNodeStats().getCHKInsertTotalBytesSent();
+ long totalBytesSentSSKInserts = node.getNodeStats().getSSKInsertTotalBytesSent();
+ long totalBytesSentOfferedKeys = node.getNodeStats().getOfferedKeysTotalBytesSent();
+ long totalBytesSendOffers = node.getNodeStats().getOffersSentBytesSent();
+ long totalBytesSentSwapOutput = node.getNodeStats().getSwappingTotalBytesSent();
+ long totalBytesSentAuth = node.getNodeStats().getTotalAuthBytesSent();
+ long totalBytesSentAckOnly = node.getNodeStats().getNotificationOnlyPacketsSentBytes();
+ long totalBytesSentResends = node.getNodeStats().getResendBytesSent();
+ long totalBytesSentUOM = node.getNodeStats().getUOMBytesSent();
+ long totalBytesSentAnnounce = node.getNodeStats().getAnnounceBytesSent();
+ long totalBytesSentAnnouncePayload = node.getNodeStats().getAnnounceBytesPayloadSent();
+ long totalBytesSentRoutingStatus = node.getNodeStats().getRoutingStatusBytes();
+ long totalBytesSentNetworkColoring = node.getNodeStats().getNetworkColoringSentBytes();
+ long totalBytesSentPing = node.getNodeStats().getPingSentBytes();
+ long totalBytesSentProbeRequest = node.getNodeStats().getProbeRequestSentBytes();
+ long totalBytesSentRouted = node.getNodeStats().getRoutedMessageSentBytes();
+ long totalBytesSentDisconn = node.getNodeStats().getDisconnBytesSent();
+ long totalBytesSentInitial = node.getNodeStats().getInitialMessagesBytesSent();
+ long totalBytesSentChangedIP = node.getNodeStats().getChangedIPBytesSent();
+ long totalBytesSentNodeToNode = node.getNodeStats().getNodeToNodeBytesSent();
+ long totalBytesSentAllocationNotices = node.getNodeStats().getAllocationNoticesBytesSent();
+ long totalBytesSentFOAF = node.getNodeStats().getFOAFBytesSent();
long totalBytesSentRemaining = total[0] -
(totalPayload + totalBytesSentCHKRequests + totalBytesSentSSKRequests +
totalBytesSentCHKInserts + totalBytesSentSSKInserts +
@@ -368,7 +368,7 @@ public int compare(PeerNodeStatus firstNode, PeerNodeStatus secondNode) {
textBuilder.append(l10n("foafBytes", "total", SizeUtil.formatSize(totalBytesSentFOAF, true))).append("\n");
textBuilder.append(l10n("unaccountedBytes", new String[] { "total", "percent" },
new String[] { SizeUtil.formatSize(totalBytesSentRemaining, true), Integer.toString((int)(totalBytesSentRemaining*100 / total[0])) })).append("\n");
- double sentOverheadPerSecond = node.nodeStats.getSentOverheadPerSecond();
+ double sentOverheadPerSecond = node.getNodeStats().getSentOverheadPerSecond();
textBuilder.append(l10n("totalOverhead", new String[] { "rate", "percent" },
new String[] { SizeUtil.formatSize((long)sentOverheadPerSecond), Integer.toString((int)((100 * sentOverheadPerSecond) / total_output_rate)) })).append("\n");
}
@@ -376,7 +376,7 @@ public int compare(PeerNodeStatus firstNode, PeerNodeStatus secondNode) {
// showStartingPlugins
textBuilder.append("Plugins:\n");
- PluginManager pm = node.pluginManager;
+ PluginManager pm = node.getPluginManager();
if (!pm.getPlugins().isEmpty()) {
textBuilder.append(baseL10n.getString("PluginToadlet.pluginListTitle")).append("\n");
for(PluginInfoWrapper pi: pm.getPlugins()) {
diff --git a/src/freenet/clients/http/ExternalLinkToadlet.java b/src/freenet/clients/http/ExternalLinkToadlet.java
index 93636f6d680..da7db22717b 100644
--- a/src/freenet/clients/http/ExternalLinkToadlet.java
+++ b/src/freenet/clients/http/ExternalLinkToadlet.java
@@ -57,7 +57,7 @@ public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx) th
//Confirm whether the user really means to access an HTTP link.
//Only render status and navigation bars if the user has completed the wizard.
- boolean renderBars = node.clientCore.getToadletContainer().fproxyHasCompletedWizard();
+ boolean renderBars = node.getClientCore().getToadletContainer().fproxyHasCompletedWizard();
PageNode page = ctx.getPageMaker().getPageNode(l10n("confirmExternalLinkTitle"), ctx, new RenderParameters().renderNavigationLinks(renderBars).renderStatus(renderBars));
HTMLNode pageNode = page.outer;
HTMLNode contentNode = page.content;
diff --git a/src/freenet/clients/http/FProxyToadlet.java b/src/freenet/clients/http/FProxyToadlet.java
index 63bc00a9831..480148b3050 100644
--- a/src/freenet/clients/http/FProxyToadlet.java
+++ b/src/freenet/clients/http/FProxyToadlet.java
@@ -12,6 +12,7 @@
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@@ -86,6 +87,7 @@ public final class FProxyToadlet extends Toadlet implements RequestClient {
"image/png",
"image/jpeg",
"image/gif",
+ "image/webp",
"audio/mp3",
"audio/ogg",
"video/ogg",
@@ -126,7 +128,7 @@ public FProxyToadlet(final HighLevelSimpleClient client, NodeClientCore core, FP
client.setMaxLength(MAX_LENGTH_NO_PROGRESS);
client.setMaxIntermediateLength(MAX_LENGTH_NO_PROGRESS);
this.core = core;
- this.context = core.clientContext;
+ this.context = core.getClientContext();
fetchTracker = tracker;
}
@@ -219,7 +221,7 @@ private void handleDownload(ToadletContext context, Bucket data, BucketFactory b
NodeL10n.getBase().addL10nSubstitution(option, "FProxyToadlet.backToFProxy", new String[] { "link" },
new HTMLNode[] { HTMLNode.link("/") });
- byte[] pageBytes = pageNode.generate().getBytes("UTF-8");
+ byte[] pageBytes = pageNode.generate().getBytes(StandardCharsets.UTF_8);
context.sendReplyHeaders(200, "OK", new MultiValueTable(), "text/html; charset=utf-8", pageBytes.length);
context.writeData(pageBytes);
return;
@@ -300,12 +302,12 @@ private void handleDownload(ToadletContext context, Bucket data, BucketFactory b
private static void addDownloadOptions(ToadletContext ctx, HTMLNode optionList, FreenetURI key, String mimeType,
boolean disableFiltration, boolean dontShowFilter, NodeClientCore core) {
- PHYSICAL_THREAT_LEVEL threatLevel = core.node.securityLevels.getPhysicalThreatLevel();
- NETWORK_THREAT_LEVEL netLevel = core.node.securityLevels.getNetworkThreatLevel();
+ PHYSICAL_THREAT_LEVEL threatLevel = core.getNode().getSecurityLevels().getPhysicalThreatLevel();
+ NETWORK_THREAT_LEVEL netLevel = core.getNode().getSecurityLevels().getNetworkThreatLevel();
boolean filterChecked = !(((threatLevel == PHYSICAL_THREAT_LEVEL.LOW &&
netLevel == NETWORK_THREAT_LEVEL.LOW)) || disableFiltration);
if((filterChecked) && mimeType != null && !mimeType.equals("application/octet-stream") &&
- !mimeType.equals("")) {
+ !mimeType.isEmpty()) {
FilterMIMEType type = ContentFilter.getMIMEType(mimeType);
if((type == null || (!(type.safeToRead || type.readFilter != null))) &&
!(threatLevel == PHYSICAL_THREAT_LEVEL.HIGH ||
@@ -328,7 +330,7 @@ private static void addDownloadOptions(ToadletContext ctx, HTMLNode optionList,
optionForm.addChild("input",
new String[] { "type", "name", "value" },
new String[] { "hidden", "persistence", "forever" });
- if (mimeType != null && !mimeType.equals("")) {
+ if (mimeType != null && !mimeType.isEmpty()) {
optionForm.addChild("input",
new String[] { "type", "name", "value" },
new String[] { "hidden", "type", mimeType });
@@ -387,7 +389,7 @@ private static void addDownloadOptions(ToadletContext ctx, HTMLNode optionList,
optionForm.addChild("input",
new String[] { "type", "name", "value" },
new String[] { "hidden", "persistence", "forever" });
- if (mimeType != null && !mimeType.equals("")) {
+ if (mimeType != null && !mimeType.isEmpty()) {
optionForm.addChild("input",
new String[] { "type", "name", "value" },
new String[] { "hidden", "type", mimeType });
@@ -446,7 +448,7 @@ private void innerHandleMethodGET(URI uri, HTTPRequest httprequest, ToadletConte
final String accept = headers.get("accept");
if(logMINOR) Logger.minor(this, "UA = "+ua+" accept = "+accept);
final boolean canSendProgress =
- isBrowser(ua) && !ctx.disableProgressPage() && (accept == null || accept.indexOf("text/html") > -1) && !httprequest.isParameterSet("forcedownload");
+ isBrowser(ua) && !ctx.disableProgressPage() && (accept == null || accept.contains("text/html")) && !httprequest.isParameterSet("forcedownload");
long defaultMaxSize = canSendProgress ? MAX_LENGTH_WITH_PROGRESS : MAX_LENGTH_NO_PROGRESS;
@@ -515,7 +517,7 @@ private void innerHandleMethodGET(URI uri, HTTPRequest httprequest, ToadletConte
} else if(ks.startsWith("/feed/") || ks.equals("/feed")) {
String schemeHostAndPort = getSchemeHostAndPort(ctx);
String atom = ctx.getAlertManager().getAtom(schemeHostAndPort);
- byte[] buf = atom.getBytes("UTF-8");
+ byte[] buf = atom.getBytes(StandardCharsets.UTF_8);
ctx.sendReplyHeadersFProxy(200, "OK", null, "application/atom+xml", buf.length);
ctx.writeData(buf, 0, buf.length);
return;
@@ -624,7 +626,7 @@ public void onText(String text, String type, URI baseURI) {
@Override
public void onFinishedPage() {
- core.node.executor.execute(new Runnable() {
+ core.getNode().getExecutor().execute(new Runnable() {
@Override
public void run() {
@@ -646,12 +648,12 @@ public void run() {
String override = (requestedMimeType == null) ? "" : "?type="+URLEncoder.encode(requestedMimeType,true);
String maybeCharset = httprequest.isParameterSet("maybecharset") ? httprequest.getParam("maybecharset", null) : null;
fctx.charset = maybeCharset;
- if(override.equals("") && maybeCharset != null)
+ if(override.isEmpty() && maybeCharset != null)
override = "?maybecharset="+URLEncoder.encode(maybeCharset, true);
// No point passing ?force= across a redirect, since the key will change.
// However, there is every point in passing ?forcedownload.
if(httprequest.isParameterSet("forcedownload")) {
- if(override.length() == 0) override = "?forcedownload";
+ if(override.isEmpty()) override = "?forcedownload";
else override = override+"&forcedownload";
}
@@ -912,7 +914,7 @@ public void run() {
PluginInfoWrapper keyUtil;
if((e.mode == FetchExceptionMode.NOT_IN_ARCHIVE || e.mode == FetchExceptionMode.NOT_ENOUGH_PATH_COMPONENTS)) {
// first look for the newest version
- if ((keyUtil = core.node.pluginManager.getPluginInfo("plugins.KeyUtils.KeyUtilsPlugin")) != null) {
+ if ((keyUtil = core.getNode().getPluginManager().getPluginInfo("plugins.KeyUtils.KeyUtilsPlugin")) != null) {
option = optionList.addChild("li");
if (keyUtil.getPluginLongVersion() < 5010)
NodeL10n.getBase().addL10nSubstitution(option, "FProxyToadlet.openWithKeyExplorer", new String[] { "link" }, new HTMLNode[] { HTMLNode.link("/KeyUtils/?automf=true&key=" + key.toString()) });
@@ -921,7 +923,7 @@ public void run() {
option = optionList.addChild("li");
NodeL10n.getBase().addL10nSubstitution(option, "FProxyToadlet.openWithSiteExplorer", new String[] { "link" }, new HTMLNode[] { HTMLNode.link("/KeyUtils/Site?key=" + key.toString()) });
}
- } else if ((keyUtil = core.node.pluginManager.getPluginInfo("plugins.KeyExplorer.KeyExplorer")) != null) {
+ } else if ((keyUtil = core.getNode().getPluginManager().getPluginInfo("plugins.KeyExplorer.KeyExplorer")) != null) {
option = optionList.addChild("li");
if (keyUtil.getPluginLongVersion() > 4999)
NodeL10n.getBase().addL10nSubstitution(option, "FProxyToadlet.openWithKeyExplorer", new String[] { "link" }, new HTMLNode[] { HTMLNode.link("/KeyExplorer/?automf=true&key=" + key.toString())});
@@ -930,7 +932,7 @@ public void run() {
}
}
if(filterException != null) {
- if((mime.equals("application/x-freenet-index")) && (core.node.pluginManager.isPluginLoaded("plugins.ThawIndexBrowser.ThawIndexBrowser"))) {
+ if((mime.equals("application/x-freenet-index")) && (core.getNode().getPluginManager().isPluginLoaded("plugins.ThawIndexBrowser.ThawIndexBrowser"))) {
option = optionList.addChild("li");
NodeL10n.getBase().addL10nSubstitution(option, "FProxyToadlet.openAsThawIndex", new String[] { "link" }, new HTMLNode[] { HTMLNode.link("/plugins/plugins.ThawIndexBrowser.ThawIndexBrowser/?key=" + key.toString())});
}
@@ -981,7 +983,7 @@ public void run() {
private String getSchemeHostAndPort(ToadletContext ctx) {
// retrieve config from froxy
- SubConfig fProxyConfig = core.node.config.get("fproxy");
+ SubConfig fProxyConfig = core.getNode().getConfig().get("fproxy");
Option> fProxyPort = fProxyConfig.getOption("port");
Option> fProxyBindTo = fProxyConfig.getOption("bindTo");
@@ -1039,7 +1041,7 @@ private String getLink(FreenetURI uri, String requestedMimeType, long maxSize, S
sb.append("/");
sb.append(uri.toASCIIString());
char c = '?';
- if(requestedMimeType != null && requestedMimeType.length() != 0) {
+ if(requestedMimeType != null && !requestedMimeType.isEmpty()) {
sb.append(c).append("type=").append(URLEncoder.encode(requestedMimeType,false)); c = '&';
}
if(maxSize > 0 && appendMaxSize) {
@@ -1065,12 +1067,12 @@ private String sanitizeReferer(ToadletContext ctx) {
URI refererURI = new URI(URIPreEncoder.encode(referer));
String path = refererURI.getPath();
while(path.startsWith("/")) path = path.substring(1);
- if("".equals(path)) return "/";
+ if(path.isEmpty()) return "/";
FreenetURI furi = new FreenetURI(path);
HTTPRequest req = new HTTPRequestImpl(refererURI, "GET");
String type = req.getParam("type");
referer = "/" + furi.toString();
- if(type != null && type.length() > 0)
+ if(type != null && !type.isEmpty())
referer += "?type=" + type;
} catch (MalformedURLException e) {
referer = "/";
@@ -1088,8 +1090,8 @@ private static String getForceValue(FreenetURI key, long time) {
try{
bos.write(random);
- bos.write(key.toString().getBytes("UTF-8"));
- bos.write(Long.toString(time / FORCE_GRAIN_INTERVAL).getBytes("UTF-8"));
+ bos.write(key.toString().getBytes(StandardCharsets.UTF_8));
+ bos.write(Long.toString(time / FORCE_GRAIN_INTERVAL).getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
throw new Error(e);
}
@@ -1106,9 +1108,9 @@ public static void maybeCreateFProxyEtc(NodeClientCore core, Node node, Config c
HighLevelSimpleClient client = core.makeClient(RequestStarter.INTERACTIVE_PRIORITY_CLASS, true, true);
random = new byte[32];
- core.random.nextBytes(random);
+ core.getRandom().nextBytes(random);
- FProxyFetchTracker fetchTracker = new FProxyFetchTracker(core.clientContext, client.getFetchContext(),
+ FProxyFetchTracker fetchTracker = new FProxyFetchTracker(core.getClientContext(), client.getFetchContext(),
new RequestClientBuilder().realTime().build());
@@ -1174,7 +1176,7 @@ public static void maybeCreateFProxyEtc(NodeClientCore core, Node node, Config c
server.register(seclevels, "FProxyToadlet.categoryConfig", "/seclevels/", true,
"FProxyToadlet.seclevelsTitle", "FProxyToadlet.seclevels", true, null);
- if(node.pluginManager.isEnabled()) {
+ if(node.getPluginManager().isEnabled()) {
PproxyToadlet pproxy = new PproxyToadlet(client, node);
server.register(pproxy, "FProxyToadlet.categoryConfig", "/plugins/", true, "FProxyToadlet.pluginsTitle",
"FProxyToadlet.plugins", true, null);
@@ -1214,7 +1216,7 @@ public static void maybeCreateFProxyEtc(NodeClientCore core, Node node, Config c
server.register(opennetToadlet, "FProxyToadlet.categoryStatus", "/strangers/", true,
"FProxyToadlet.opennetTitle", "FProxyToadlet.opennet", true, opennetToadlet);
- ChatForumsToadlet chatForumsToadlet = new ChatForumsToadlet(client, node.pluginManager);
+ ChatForumsToadlet chatForumsToadlet = new ChatForumsToadlet(client, node.getPluginManager());
server.register(chatForumsToadlet, "FProxyToadlet.categoryChat", "/chat/", true,
"FProxyToadlet.chatForumsTitle", "FProxyToadlet.chatForums", true, chatForumsToadlet);
@@ -1305,7 +1307,7 @@ private static long[] parseRange(String hdrrange) throws HTTPRangeException {
result[0] = Long.parseLong(range[0]);
if (result[0] < 0)
throw new HTTPRangeException("Negative 'from' value");
- if (range[1].trim().length() > 0) {
+ if (!range[1].trim().isEmpty()) {
result[1] = Long.parseLong(range[1]);
if (result[1] <= result[0])
throw new HTTPRangeException("'from' value must be less then 'to' value");
diff --git a/src/freenet/clients/http/FileInsertWizardToadlet.java b/src/freenet/clients/http/FileInsertWizardToadlet.java
index 37beaeb2971..ae4be1fe01c 100644
--- a/src/freenet/clients/http/FileInsertWizardToadlet.java
+++ b/src/freenet/clients/http/FileInsertWizardToadlet.java
@@ -85,13 +85,15 @@ private HTMLNode createInsertBox (PageMaker pageMaker, ToadletContext ctx, boole
HTMLNode insertBox = infobox.outer;
HTMLNode insertContent = infobox.content;
insertContent.addChild("p", l10n("insertIntro"));
- NETWORK_THREAT_LEVEL seclevel = core.node.securityLevels.getNetworkThreatLevel();
+ NETWORK_THREAT_LEVEL seclevel = core.getNode().getSecurityLevels().getNetworkThreatLevel();
HTMLNode insertForm = ctx.addFormChild(insertContent, QueueToadlet.PATH_UPLOADS, "queueInsertForm");
+ boolean preselectSsk = (!rememberedLastTime && seclevel != NETWORK_THREAT_LEVEL.LOW)
+ || (rememberedLastTime && !wasCanonicalLastTime)
+ || seclevel == NETWORK_THREAT_LEVEL.MAXIMUM;
HTMLNode input = insertForm.addChild("input",
new String[] { "type", "name", "value", "id" },
new String[] { "radio", "keytype", "CHK", "keytypeChk" });
- if ((!rememberedLastTime && seclevel == NETWORK_THREAT_LEVEL.LOW) ||
- (rememberedLastTime && wasCanonicalLastTime && seclevel != NETWORK_THREAT_LEVEL.MAXIMUM)) {
+ if (!preselectSsk) {
input.addAttribute("checked", "checked");
}
insertForm.addChild("label",
@@ -105,7 +107,7 @@ private HTMLNode createInsertBox (PageMaker pageMaker, ToadletContext ctx, boole
input = insertForm.addChild("input",
new String[] { "type", "name", "value", "id" },
new String[] { "radio", "keytype", "SSK", "keytypeSsk" });
- if (seclevel == NETWORK_THREAT_LEVEL.MAXIMUM || (rememberedLastTime && !wasCanonicalLastTime)) {
+ if (preselectSsk) {
input.addAttribute("checked", "checked");
}
insertForm.addChild("label",
diff --git a/src/freenet/clients/http/FirstTimeWizardNewToadlet.java b/src/freenet/clients/http/FirstTimeWizardNewToadlet.java
index 8ccb30646ed..eb0d0de802f 100644
--- a/src/freenet/clients/http/FirstTimeWizardNewToadlet.java
+++ b/src/freenet/clients/http/FirstTimeWizardNewToadlet.java
@@ -59,7 +59,7 @@ public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx)
// if threat level is high, the password must already be set: user is running the wizard again?
isPasswordAlreadySet =
- core.node.securityLevels.getPhysicalThreatLevel() == SecurityLevels.PHYSICAL_THREAT_LEVEL.HIGH;
+ core.getNode().getSecurityLevels().getPhysicalThreatLevel() == SecurityLevels.PHYSICAL_THREAT_LEVEL.HIGH;
showForm(ctx, new FormModel().toModel());
}
@@ -111,9 +111,9 @@ private class FormModel {
private String haveMonthlyLimit = "";
- private String downloadLimit = "900";
+ private String downloadLimit = "1024";
- private String uploadLimit = "100";
+ private String uploadLimit = "160";
private String bandwidthMonthlyLimit = "500";
@@ -254,7 +254,7 @@ private boolean isValid() {
private void detectBandwidthLimit() {
try {
BandwidthLimit detected =
- BandwidthManipulator.detectBandwidthLimits(core.node.ipDetector.getBandwidthIndicator());
+ BandwidthManipulator.detectBandwidthLimits(core.getNode().getIpDetector().getBandwidthIndicator());
// Detected limits reasonable; add half of both as recommended option.
downloadLimitDetected = Long.toString(detected.downBytes / 2 / KiB);
@@ -293,15 +293,15 @@ private Map toModel() {
private void save() {
if (knowSomeone.isEmpty()) {
- // Opennet
- core.node.securityLevels.setThreatLevel(SecurityLevels.NETWORK_THREAT_LEVEL.LOW);
+ // Opennet + Darknet (possible)
+ core.getNode().getSecurityLevels().setThreatLevel(SecurityLevels.NETWORK_THREAT_LEVEL.NORMAL);
} else {
if (connectToStrangers.isEmpty()) {
// Darknet
- core.node.securityLevels.setThreatLevel(SecurityLevels.NETWORK_THREAT_LEVEL.HIGH);
+ core.getNode().getSecurityLevels().setThreatLevel(SecurityLevels.NETWORK_THREAT_LEVEL.HIGH);
} else {
// Opennet + Darknet
- core.node.securityLevels.setThreatLevel(SecurityLevels.NETWORK_THREAT_LEVEL.NORMAL);
+ core.getNode().getSecurityLevels().setThreatLevel(SecurityLevels.NETWORK_THREAT_LEVEL.NORMAL);
}
}
@@ -323,11 +323,11 @@ private void save() {
if (!isPasswordAlreadySet) {
try {
if (setPassword.isEmpty()) { // no password protection requested
- core.node.securityLevels.setThreatLevel(SecurityLevels.PHYSICAL_THREAT_LEVEL.NORMAL);
- core.node.setMasterPassword("", true);
+ core.getNode().getSecurityLevels().setThreatLevel(SecurityLevels.PHYSICAL_THREAT_LEVEL.NORMAL);
+ core.getNode().setMasterPassword("", true);
} else {
- core.node.securityLevels.setThreatLevel(SecurityLevels.PHYSICAL_THREAT_LEVEL.HIGH);
- core.node.setMasterPassword(password, true);
+ core.getNode().getSecurityLevels().setThreatLevel(SecurityLevels.PHYSICAL_THREAT_LEVEL.HIGH);
+ core.getNode().setMasterPassword(password, true);
}
} catch (Node.AlreadySetPasswordException | MasterKeysWrongPasswordException | MasterKeysFileSizeException | IOException e) {
Logger.error(this, "Should not happen, please report! " + e, e);
diff --git a/src/freenet/clients/http/FirstTimeWizardToadlet.java b/src/freenet/clients/http/FirstTimeWizardToadlet.java
index bd9159de9ab..025deede5dd 100644
--- a/src/freenet/clients/http/FirstTimeWizardToadlet.java
+++ b/src/freenet/clients/http/FirstTimeWizardToadlet.java
@@ -81,7 +81,7 @@ public enum WIZARD_PRESET {
//Generic Toadlet-related initialization.
super(client);
this.core = core;
- Config config = node.config;
+ Config config = node.getConfig();
addWizardConfiguration(config);
@@ -187,7 +187,7 @@ public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx) th
super.writeTemporaryRedirect(ctx, "Need opennet choice",
persistFields.appendTo(TOADLET_URL+"?step=OPENNET"));
return;
- } else if (currentStep == WIZARD_STEP.NAME_SELECTION && core.node.isOpennetEnabled()) {
+ } else if (currentStep == WIZARD_STEP.NAME_SELECTION && core.getNode().isOpennetEnabled()) {
//Skip node name selection if not in darknet mode.
super.writeTemporaryRedirect(ctx, "Skip name selection",
persistFields.appendTo(stepURL(WIZARD_STEP.DATASTORE_SIZE.name())));
diff --git a/src/freenet/clients/http/HTTPRequestImpl.java b/src/freenet/clients/http/HTTPRequestImpl.java
index 13db8930a09..36ea2b4ce0d 100644
--- a/src/freenet/clients/http/HTTPRequestImpl.java
+++ b/src/freenet/clients/http/HTTPRequestImpl.java
@@ -18,19 +18,19 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
-import java.util.Map.Entry;
import javax.naming.SizeLimitExceededException;
import freenet.support.Fields;
import freenet.support.LogThresholdCallback;
import freenet.support.Logger;
+import freenet.support.Logger.LogLevel;
import freenet.support.MultiValueTable;
import freenet.support.SimpleReadOnlyArrayBucket;
import freenet.support.URLEncoder;
-import freenet.support.Logger.LogLevel;
import freenet.support.api.Bucket;
import freenet.support.api.BucketFactory;
import freenet.support.api.HTTPRequest;
@@ -122,7 +122,7 @@ public HTTPRequestImpl(String path, String encodedQueryString, String method) th
this.data = null;
this.parts = null;
this.bucketfactory = null;
- if ((encodedQueryString!=null) && (encodedQueryString.length()>0)) {
+ if ((encodedQueryString!=null) && !encodedQueryString.isEmpty()) {
this.uri = new URI(path+ '?' +encodedQueryString);
} else {
this.uri = new URI(path);
@@ -205,12 +205,7 @@ private void parseRequestParameters(String queryString, boolean doUrlDecoding, b
for (Entry> parameterValues : parameters.entrySet()) {
List values = parameterValues.getValue();
String value = values.get(values.size() - 1);
- byte[] buf;
- try {
- buf = value.getBytes("UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
- } // FIXME some other encoding?
+ byte[] buf = value.getBytes(StandardCharsets.UTF_8);
RandomAccessBucket b = new SimpleReadOnlyArrayBucket(buf);
parts.put(parameterValues.getKey(), b);
if(logMINOR)
@@ -277,7 +272,7 @@ public static Map> parseUriParameters(String queryString, b
Map> parameters = new HashMap>();
// nothing to do if there was no query string in the URI
- if ((queryString == null) || (queryString.length() == 0)) {
+ if ((queryString == null) || queryString.isEmpty()) {
return parameters;
}
@@ -665,11 +660,7 @@ public boolean isPartSet(String name) {
@Override
@Deprecated
public String getPartAsString(String name, int maxlength) {
- try {
- return new String(getPartAsBytes(name, maxlength), "UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
- }
+ return new String(getPartAsBytes(name, maxlength), StandardCharsets.UTF_8);
}
@Override
@@ -694,11 +685,7 @@ public String getPartAsStringFailsafe(String name, int maxLength) {
}
private String getPartAsLimitedString(Bucket part, int maxLength) {
- try {
- return new String(getPartAsLimitedBytes(part, maxLength), "UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
- }
+ return new String(getPartAsLimitedBytes(part, maxLength), StandardCharsets.UTF_8);
}
/* (non-Javadoc)
@@ -890,7 +877,7 @@ public String[] getParts() {
@Override
public boolean isIncognito() {
if(isParameterSet("incognito"))
- return Boolean.valueOf(getParam("incognito"));
+ return Boolean.parseBoolean(getParam("incognito"));
return false;
}
diff --git a/src/freenet/clients/http/IntervalPusherManager.java b/src/freenet/clients/http/IntervalPusherManager.java
index fd3795f11d5..ea7f1275275 100644
--- a/src/freenet/clients/http/IntervalPusherManager.java
+++ b/src/freenet/clients/http/IntervalPusherManager.java
@@ -31,7 +31,7 @@ public void run() {
}
// If there are more elements, it reschedules
- if (elements.size() > 0) {
+ if (!elements.isEmpty()) {
ticker.queueTimedJob(this, "Stats refresher", REFRESH_PERIOD, false, true);
}
}
@@ -61,7 +61,7 @@ public IntervalPusherManager(Ticker ticker, PushDataManager pushDataManager) {
*/
public void registerUpdateableElement(BaseUpdateableElement element) {
boolean needsStart = false;
- if (elements.size() == 0) {
+ if (elements.isEmpty()) {
needsStart = true;
}
elements.add(element);
diff --git a/src/freenet/clients/http/LocalFileBrowserToadlet.java b/src/freenet/clients/http/LocalFileBrowserToadlet.java
index 42cf7dc93c1..1a4ba64cc42 100644
--- a/src/freenet/clients/http/LocalFileBrowserToadlet.java
+++ b/src/freenet/clients/http/LocalFileBrowserToadlet.java
@@ -7,6 +7,7 @@
import freenet.l10n.NodeL10n;
import freenet.node.NodeClientCore;
import freenet.support.HTMLNode;
+import freenet.support.SizeUtil;
import freenet.support.api.HTTPRequest;
import java.io.File;
@@ -274,7 +275,7 @@ private void renderPage (Hashtable fieldPairs, String path, fina
}
}
- if (path.length() == 0) {
+ if (path.isEmpty()) {
if (lastSuccessful != null && lastSuccessful.isDirectory() && allowedDir(lastSuccessful)) {
path = lastSuccessful.getAbsolutePath();
} else {
@@ -333,7 +334,7 @@ public int compare(File firstFile, File secondFile) {
return firstFile.getName().compareToIgnoreCase(secondFile.getName());
}
});
- HTMLNode listingTable = listingDiv.addChild("table");
+ HTMLNode listingTable = listingDiv.addChild("table", "class", "directory-listing");
HTMLNode headerRow = listingTable.addChild("tr");
headerRow.addChild("th");
headerRow.addChild("th", l10n("fileHeader"));
@@ -406,13 +407,13 @@ public int compare(File firstFile, File secondFile) {
fileRow.addChild("td", currentFile.getName());
fileRow.addChild("td", "class", "right-align",
- String.valueOf(currentFile.length()));
+ SizeUtil.formatSize(currentFile.length(), true));
} else {
fileRow.addChild("td");
fileRow.addChild("td", "class", "unreadable-file",
currentFile.getName());
fileRow.addChild("td", "class", "right-align",
- String.valueOf(currentFile.length()));
+ SizeUtil.formatSize(currentFile.length(), true));
}
}
}
diff --git a/src/freenet/clients/http/LocalFileInsertToadlet.java b/src/freenet/clients/http/LocalFileInsertToadlet.java
index 6e67483c1f3..01a49f51800 100644
--- a/src/freenet/clients/http/LocalFileInsertToadlet.java
+++ b/src/freenet/clients/http/LocalFileInsertToadlet.java
@@ -54,7 +54,7 @@ protected Hashtable persistenceFields (Hashtable
}
String element = set.get("compress");
- if (element != null && Boolean.valueOf(element)) {
+ if (element != null && Boolean.parseBoolean(element)) {
fieldPairs.put("compress", element);
}
diff --git a/src/freenet/clients/http/N2NTMToadlet.java b/src/freenet/clients/http/N2NTMToadlet.java
index a54a72e27d2..996944ea17e 100644
--- a/src/freenet/clients/http/N2NTMToadlet.java
+++ b/src/freenet/clients/http/N2NTMToadlet.java
@@ -156,7 +156,7 @@ public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx)
DarknetPeerNode[] peerNodes = node.getDarknetConnections();
if(request.isPartSet(LocalFileBrowserToadlet.selectFile)) {
String fnam = request.getPartAsStringFailsafe("filename", 1024);
- if(fnam != null && fnam.length() > 0) {
+ if(fnam != null && !fnam.isEmpty()) {
filename = new File(fnam);
if(!(filename.exists() && filename.canRead())) {
peerTableInfobox.addChild("#", l10n("noSuchFileOrCannotRead"));
@@ -188,7 +188,7 @@ public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx)
} else if(request.isPartSet("n2nm-upload")) {
try{
HTTPUploadedFile file = request.getUploadedFile("n2nm-upload");
- if(!file.getFilename().equals("")) {
+ if(!file.getFilename().isEmpty()) {
long size = request.getUploadedFile("n2nm-upload").getData().size();
if(size > 0) {
long limit = maxSize();
diff --git a/src/freenet/clients/http/OpennetConnectionsToadlet.java b/src/freenet/clients/http/OpennetConnectionsToadlet.java
index 3c2bafc8cc2..b94a1ecc522 100644
--- a/src/freenet/clients/http/OpennetConnectionsToadlet.java
+++ b/src/freenet/clients/http/OpennetConnectionsToadlet.java
@@ -51,7 +51,7 @@ protected SimpleFieldSet getNoderef() {
@Override
protected PeerNodeStatus[] getPeerNodeStatuses(boolean noHeavy) {
- return node.peers.getOpennetPeerNodeStatuses(noHeavy);
+ return node.getPeers().getOpennetPeerNodeStatuses(noHeavy);
}
@Override
diff --git a/src/freenet/clients/http/PageMaker.java b/src/freenet/clients/http/PageMaker.java
index 7cb1f2e483d..5d282fdc984 100644
--- a/src/freenet/clients/http/PageMaker.java
+++ b/src/freenet/clients/http/PageMaker.java
@@ -383,7 +383,7 @@ public PageNode getPageNode(String title, ToadletContext ctx, RenderParameters r
if (renderParameters.isRenderStatus() && fullAccess) {
final HTMLNode statusBarDiv = pageDiv.addChild("div", "id", "statusbar-container").addChild("div", "id", "statusbar");
- if (node != null && node.clientCore != null) {
+ if (node != null && node.getClientCore() != null) {
final HTMLNode alerts = ctx.getAlertManager().createSummary(true);
if (alerts != null) {
statusBarDiv.addChild(alerts).addAttribute("id", "statusbar-alerts");
@@ -394,7 +394,7 @@ public PageNode getPageNode(String title, ToadletContext ctx, RenderParameters r
statusBarDiv.addChild("div", "id", "statusbar-language").addChild("a", "href", "/config/node#l10n", NodeL10n.getBase().getSelectedLanguage().fullName);
- if (node.clientCore != null && ctx != null && renderParameters.isRenderModeSwitch()) {
+ if (node.getClientCore() != null && ctx != null && renderParameters.isRenderModeSwitch()) {
boolean isAdvancedMode = ctx.isAdvancedModeEnabled();
String uri = ctx.getUri().getQuery();
Map> parameters = HTTPRequestImpl.parseUriParameters(uri, true);
@@ -409,28 +409,28 @@ public PageNode getPageNode(String title, ToadletContext ctx, RenderParameters r
switchMode.addChild("a", "href", "?" + HTTPRequestImpl.createQueryString(parameters, false), isAdvancedMode ? NodeL10n.getBase().getString("StatusBar.switchToSimpleMode") : NodeL10n.getBase().getString("StatusBar.switchToAdvancedMode"));
}
- if (node != null && node.clientCore != null) {
+ if (node != null && node.getClientCore() != null) {
statusBarDiv.addChild("div", "class", "separator", "\u00a0");
final HTMLNode secLevels = statusBarDiv.addChild("div", "id", "statusbar-seclevels", NodeL10n.getBase().getString("SecurityLevels.statusBarPrefix"));
- final HTMLNode network = secLevels.addChild("a", "href", "/seclevels/", SecurityLevels.localisedName(node.securityLevels.getNetworkThreatLevel()) + "\u00a0");
+ final HTMLNode network = secLevels.addChild("a", "href", "/seclevels/", SecurityLevels.localisedName(node.getSecurityLevels().getNetworkThreatLevel()) + "\u00a0");
network.addAttribute("title", NodeL10n.getBase().getString("SecurityLevels.networkThreatLevelShort"));
- network.addAttribute("class", node.securityLevels.getNetworkThreatLevel().toString().toLowerCase());
+ network.addAttribute("class", node.getSecurityLevels().getNetworkThreatLevel().toString().toLowerCase());
- final HTMLNode physical = secLevels.addChild("a", "href", "/seclevels/", SecurityLevels.localisedName(node.securityLevels.getPhysicalThreatLevel()));
+ final HTMLNode physical = secLevels.addChild("a", "href", "/seclevels/", SecurityLevels.localisedName(node.getSecurityLevels().getPhysicalThreatLevel()));
physical.addAttribute("title", NodeL10n.getBase().getString("SecurityLevels.physicalThreatLevelShort"));
- physical.addAttribute("class", node.securityLevels.getPhysicalThreatLevel().toString().toLowerCase());
+ physical.addAttribute("class", node.getSecurityLevels().getPhysicalThreatLevel().toString().toLowerCase());
statusBarDiv.addChild("div", "class", "separator", "\u00a0");
- final int connectedPeers = node.peers.countConnectedPeers();
+ final int connectedPeers = node.getPeers().countConnectedPeers();
int darknetTotal = 0;
- for(DarknetPeerNode n : node.peers.getDarknetPeers()) {
+ for(DarknetPeerNode n : node.getPeers().getDarknetPeers()) {
if(n == null) continue;
if(n.isDisabled()) continue;
darknetTotal++;
}
- final int connectedDarknetPeers = node.peers.countConnectedDarknetPeers();
+ final int connectedDarknetPeers = node.getPeers().countConnectedDarknetPeers();
final int totalPeers = (node.getOpennet() == null) ? (darknetTotal > 0 ? darknetTotal : Integer.MAX_VALUE) : node.getOpennet().getNumberOfConnectedPeersToAimIncludingDarknet();
final double connectedRatio = ((double)connectedPeers) / (double)totalPeers;
final String additionalClass;
@@ -464,7 +464,7 @@ public PageNode getPageNode(String title, ToadletContext ctx, RenderParameters r
Math.min(100,Math.floor(100*connectedRatio)) + "%;" });
progressBar.addChild("div", new String[] { "class", "title" }, new String[] { "progress_fraction_finalized", NodeL10n.getBase().getString("StatusBar.connectedPeers", new String[]{"X", "Y"},
- new String[]{Integer.toString(node.peers.countConnectedDarknetPeers()), Integer.toString(node.peers.countConnectedOpennetPeers())}) },
+ new String[]{Integer.toString(node.getPeers().countConnectedDarknetPeers()), Integer.toString(node.getPeers().countConnectedOpennetPeers())}) },
Integer.toString(connectedPeers) + ((totalPeers != Integer.MAX_VALUE) ? " / " + Integer.toString(totalPeers) : ""));
}
}
diff --git a/src/freenet/clients/http/PproxyToadlet.java b/src/freenet/clients/http/PproxyToadlet.java
index d413edcbf4b..74cb3d48a67 100644
--- a/src/freenet/clients/http/PproxyToadlet.java
+++ b/src/freenet/clients/http/PproxyToadlet.java
@@ -79,9 +79,9 @@ public void handleMethodPOST(URI uri, final HTTPRequest request, ToadletContext
if(logMINOR) Logger.minor(this, "Pproxy received POST on "+path);
- final PluginManager pm = node.pluginManager;
+ final PluginManager pm = node.getPluginManager();
- if(path.length()>0)
+ if(!path.isEmpty())
{
// Plugins handle their own formPassword checking.
try
@@ -134,12 +134,11 @@ public void handleMethodPOST(URI uri, final HTTPRequest request, ToadletContext
if (request.isPartSet("submit-official")) {
final String pluginName = request.getPartAsStringFailsafe("plugin-name", 40);
- final String pluginSource = request.getPartAsStringFailsafe("pluginSource", 10);
-
- node.executor.execute(new Runnable() {
+
+ node.getExecutor().execute(new Runnable() {
@Override
public void run() {
- pm.startPluginOfficial(pluginName, true, true, "https".equals(pluginSource));
+ pm.startPluginOfficial(pluginName, true);
}
});
@@ -151,7 +150,7 @@ public void run() {
final String pluginName = request.getPartAsStringFailsafe("plugin-url", 200);
final boolean fileonly = "on".equalsIgnoreCase(request.getPartAsStringFailsafe("fileonly", 20));
- node.executor.execute(new Runnable() {
+ node.getExecutor().execute(new Runnable() {
@Override
public void run() {
if (fileonly)
@@ -168,7 +167,7 @@ public void run() {
if (request.isPartSet("submit-freenet")) {
final String pluginName = request.getPartAsStringFailsafe("plugin-uri", 300);
- node.executor.execute(new Runnable() {
+ node.getExecutor().execute(new Runnable() {
@Override
public void run() {
pm.startPluginFreenet(pluginName, true);
@@ -184,7 +183,7 @@ public void run() {
ctx.sendReplyHeaders(302, "Found", headers, null, 0);
return;
}
- if (request.getPartAsStringFailsafe("unloadconfirm", MAX_PLUGIN_NAME_LENGTH).length() > 0) {
+ if (!request.getPartAsStringFailsafe("unloadconfirm", MAX_PLUGIN_NAME_LENGTH).isEmpty()) {
String pluginThreadName = request.getPartAsStringFailsafe("unloadconfirm", MAX_PLUGIN_NAME_LENGTH);
String pluginSpecification = getPluginSpecification(pm, pluginThreadName);
pm.killPlugin(pluginThreadName, MAX_THREADED_UNLOAD_WAIT_TIME, false);
@@ -205,7 +204,7 @@ public void run() {
infoboxContent.addChild("a", "href", "/plugins/", l10n("returnToPluginPage"));
writeHTMLReply(ctx, 200, "OK", pageNode.generate());
return;
- }if (request.getPartAsStringFailsafe("unload", MAX_PLUGIN_NAME_LENGTH).length() > 0) {
+ }if (!request.getPartAsStringFailsafe("unload", MAX_PLUGIN_NAME_LENGTH).isEmpty()) {
PageNode page = pageMaker.getPageNode(l10n("plugins"), ctx);
HTMLNode pageNode = page.outer;
HTMLNode contentNode = page.content;
@@ -225,7 +224,7 @@ public void run() {
tempNode.addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "cancel", NodeL10n.getBase().getString("Toadlet.cancel") });
writeHTMLReply(ctx, 200, "OK", pageNode.generate());
return;
- } else if (request.getPartAsStringFailsafe("reload", MAX_PLUGIN_NAME_LENGTH).length() > 0) {
+ } else if (!request.getPartAsStringFailsafe("reload", MAX_PLUGIN_NAME_LENGTH).isEmpty()) {
PageNode page = pageMaker.getPageNode(l10n("plugins"), ctx);
HTMLNode pageNode = page.outer;
HTMLNode contentNode = page.content;
@@ -247,7 +246,7 @@ public void run() {
writeHTMLReply(ctx, 200, "OK", pageNode.generate());
return;
- } else if (request.getPartAsStringFailsafe("update", MAX_PLUGIN_NAME_LENGTH).length() > 0) {
+ } else if (!request.getPartAsStringFailsafe("update", MAX_PLUGIN_NAME_LENGTH).isEmpty()) {
// Deploy the plugin update
final String pluginFilename = request.getPartAsStringFailsafe("update", MAX_PLUGIN_NAME_LENGTH);
@@ -255,14 +254,14 @@ public void run() {
sendErrorPage(ctx, 404, l10n("pluginNotFoundUpdatingTitle"),
l10n("pluginNotFoundUpdating", "name", pluginFilename));
} else {
- node.nodeUpdater.deployPluginWhenReady(pluginFilename);
+ node.getNodeUpdater().deployPluginWhenReady(pluginFilename);
headers.put("Location", ".");
ctx.sendReplyHeaders(302, "Found", headers, null, 0);
}
return;
- }else if (request.getPartAsStringFailsafe("reloadconfirm", MAX_PLUGIN_NAME_LENGTH).length() > 0) {
+ }else if (!request.getPartAsStringFailsafe("reloadconfirm", MAX_PLUGIN_NAME_LENGTH).isEmpty()) {
boolean purge = request.isPartSet("purge");
String pluginThreadName = request.getPartAsStringFailsafe("reloadconfirm", MAX_PLUGIN_NAME_LENGTH);
final String fn = getPluginSpecification(pm, pluginThreadName);
@@ -275,7 +274,7 @@ public void run() {
if (purge) {
pm.removeCachedCopy(fn);
}
- node.executor.execute(new Runnable() {
+ node.getExecutor().execute(new Runnable() {
@Override
public void run() {
@@ -349,12 +348,12 @@ public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx)
if(path.startsWith("/")) path = path.substring(1);
if(path.startsWith("plugins/")) path = path.substring("plugins/".length());
- PluginManager pm = node.pluginManager;
+ PluginManager pm = node.getPluginManager();
if(logMINOR)
Logger.minor(this, "Pproxy fetching "+path);
try {
- if (path.equals("")) {
+ if (path.isEmpty()) {
if(!ctx.checkFullAccess(this))
return;
@@ -560,74 +559,42 @@ private void showOfficialPluginLoader(ToadletContext toadletContext, HTMLNode co
HTMLNode addOfficialForm = toadletContext.addFormChild(addOfficialPluginContent, ".", "addOfficialPluginForm");
HTMLNode p = addOfficialForm.addChild("p");
-
p.addChild("#", l10n("loadOfficialPluginText"));
- // Over Freenet or over HTTP??
-
- p.addChild("#", " " + l10n("pluginSourceChoice"));
-
- boolean loadFromWeb = pm.loadOfficialPluginsFromWeb();
-
- HTMLNode input = addOfficialForm.addChild("input",
- new String[] { "type", "name", "value", "id" },
- new String[] { "radio", "pluginSource", "freenet", "pluginSourceFreenet" });
- if(!loadFromWeb)
- input.addAttribute("checked", "true");
- addOfficialForm.addChild("label",
- new String[] { "for" },
- new String[] { "pluginSourceFreenet" },
- l10n("pluginSourceFreenet"));
- addOfficialForm.addChild("br");
- input = addOfficialForm.addChild("input",
- new String[] { "type", "name", "value", "id" },
- new String[] { "radio", "pluginSource", "https", "pluginSourceHTTPS" });
- if(loadFromWeb)
- input.addAttribute("checked", "true");
- addOfficialForm.addChild("label",
- new String[] { "for" },
- new String[] { "pluginSourceHTTPS" },
- l10n("pluginSourceHTTPS"));
- addOfficialForm.addChild("#", " ");
- if(node.getOpennet() == null)
- addOfficialForm.addChild("b").addChild("font", "color", "red", l10n("pluginSourceHTTPSWarning"));
- else
- // FIXME CSS-ize this
- addOfficialForm.addChild("b", l10n("pluginSourceHTTPSWarning"));
-
- p = addOfficialForm.addChild("p");
-
- p.addChild("#", (l10n("loadOfficialPluginLabel") + ": "));
for (Entry> groupPlugins : availablePlugins.entrySet()) {
List notLoadedPlugins = getNotLoadedPlugins(pm, groupPlugins.getValue());
if (notLoadedPlugins.isEmpty()) {
continue;
}
- HTMLNode pluginGroupNode = addOfficialForm.addChild("div", "class", "plugin-group");
- pluginGroupNode.addChild("div", "class", "plugin-group-title", l10n("pluginGroupTitle", "pluginGroup", groupPlugins.getKey()));
- for (OfficialPluginDescription pluginDescription : notLoadedPlugins) {
- if (pluginDescription.unsupported) {
- continue;
- }
- HTMLNode pluginNode = pluginGroupNode.addChild("div", "class", "plugin");
- HTMLNode option = pluginNode.addChild("input",
+ addPluginGroupForLoading(advancedModeEnabled, groupPlugins, addOfficialForm, notLoadedPlugins);
+ }
+ addOfficialForm.addChild("p").addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "submit-official", l10n("Load") });
+ }
+
+ private void addPluginGroupForLoading(boolean advancedModeEnabled, Entry> groupPlugins, HTMLNode addOfficialForm, List notLoadedPlugins) {
+ HTMLNode pluginGroupNode = addOfficialForm.addChild("div", "class", "plugin-group");
+ pluginGroupNode.addChild("div", "class", "plugin-group-title", l10n("pluginGroupTitle", "pluginGroup", groupPlugins.getKey()));
+ for (OfficialPluginDescription pluginDescription : notLoadedPlugins) {
+ if (pluginDescription.unsupported) {
+ continue;
+ }
+ HTMLNode pluginNode = pluginGroupNode.addChild("div", "class", "plugin");
+ HTMLNode option = pluginNode.addChild("input",
new String[] { "type", "name", "value", "id" },
new String[] { "radio", "plugin-name", pluginDescription.name, "radioPlugin" + pluginDescription.name });
- option.addChild("label",
+ option.addChild("label",
new String[] { "for" },
new String[] { "radioPlugin" + pluginDescription.name }
- ).addChild("i", pluginDescription.getLocalisedPluginName());
- if(pluginDescription.deprecated)
- option.addChild("b", " ("+l10n("loadLabelDeprecated")+")");
- if(pluginDescription.experimental)
- option.addChild("b", " ("+l10n("loadLabelExperimental")+")");
- if (advancedModeEnabled && pluginDescription.minimumVersion >= 0) {
- option.addChild("#", " ("+l10n("pluginVersion")+" " + pluginDescription.recommendedVersion + ")");
- }
- option.addChild("#", " - "+pluginDescription.getLocalisedPluginDescription());
+ ).addChild("i", pluginDescription.getLocalisedPluginName());
+ if (pluginDescription.deprecated)
+ option.addChild("b", " (" + l10n("loadLabelDeprecated") + ")");
+ if (pluginDescription.experimental)
+ option.addChild("b", " (" + l10n("loadLabelExperimental") + ")");
+ if (advancedModeEnabled && pluginDescription.minimumVersion >= 0) {
+ option.addChild("#", " (" + l10n("pluginVersion") + " " + pluginDescription.recommendedVersion + ")");
}
+ option.addChild("#", " - " + pluginDescription.getLocalisedPluginDescription());
}
- addOfficialForm.addChild("p").addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "submit-official", l10n("Load") });
}
private List getNotLoadedPlugins(PluginManager pluginManager, List plugins) {
diff --git a/src/freenet/clients/http/QueueToadlet.java b/src/freenet/clients/http/QueueToadlet.java
index 45011725c77..95e8a379927 100644
--- a/src/freenet/clients/http/QueueToadlet.java
+++ b/src/freenet/clients/http/QueueToadlet.java
@@ -14,7 +14,6 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
@@ -216,7 +215,7 @@ public void handleMethodPOST(URI uri, HTTPRequest request, final ToadletContext
}
MultiValueTable responseHeaders = new MultiValueTable();
responseHeaders.put("Location", LocalFileInsertToadlet.PATH+"?key="+insertURI.toASCIIString()+
- "&compress="+String.valueOf(request.getPartAsStringFailsafe("compress", 128).length() > 0)+
+ "&compress="+String.valueOf(!request.getPartAsStringFailsafe("compress", 128).isEmpty())+
"&compatibilityMode="+request.getPartAsStringFailsafe("compatibilityMode", 100)+
"&overrideSplitfileKey="+request.getPartAsStringFailsafe("overrideSplitfileKey", 65));
ctx.sendReplyHeaders(302, "Found", responseHeaders, null, 0);
@@ -229,7 +228,7 @@ public void handleMethodPOST(URI uri, HTTPRequest request, final ToadletContext
}
}
- if(request.isPartSet("delete_request") && (request.getPartAsStringFailsafe("delete_request", 128).length() > 0)) {
+ if(request.isPartSet("delete_request") && !request.getPartAsStringFailsafe("delete_request", 128).isEmpty()) {
// Confirm box
PageNode page = ctx.getPageMaker().getPageNode(l10n("confirmDeleteTitle"), ctx);
HTMLNode inner = page.content;
@@ -259,7 +258,7 @@ public void handleMethodPOST(URI uri, HTTPRequest request, final ToadletContext
line.addChild("#", filename);
}
}
- if(type != null && !type.equals("")) {
+ if(type != null && !type.isEmpty()) {
HTMLNode line = infoList.addChild("li");
boolean finalized = request.isPartSet("finalizedType");
line.addChild("#", NodeL10n.getBase().getString("FProxyToadlet."+(finalized ? "mimeType" : "expectedMimeType"), new String[] { "mime" }, new String[] { type }));
@@ -285,7 +284,7 @@ public void handleMethodPOST(URI uri, HTTPRequest request, final ToadletContext
this.writeHTMLReply(ctx, 200, "OK", page.outer.generate());
return;
- } else if(request.isPartSet("remove_request") && (request.getPartAsStringFailsafe("remove_request", 128).length() > 0)) {
+ } else if(request.isPartSet("remove_request") && !request.getPartAsStringFailsafe("remove_request", 128).isEmpty()) {
// Remove all requested (i.e. selected) requests from the queue, regardless of
// their status
// FIXME optimise into a single database job.
@@ -314,7 +313,7 @@ public void handleMethodPOST(URI uri, HTTPRequest request, final ToadletContext
}
writePermanentRedirect(ctx, "Done", path());
return;
- } else if(request.isPartSet("remove_finished_uploads_request") && (request.getPartAsStringFailsafe("remove_finished_uploads_request", 128).length() > 0)) {
+ } else if(request.isPartSet("remove_finished_uploads_request") && !request.getPartAsStringFailsafe("remove_finished_uploads_request", 128).isEmpty()) {
// Remove all finished single-file uploads
String identifier = "";
try {
@@ -343,7 +342,7 @@ public void handleMethodPOST(URI uri, HTTPRequest request, final ToadletContext
writePermanentRedirect(ctx, "Done", path());
return;
- } else if(request.isPartSet("remove_finished_downloads_request") && (request.getPartAsStringFailsafe("remove_finished_downloads_request", 128).length() > 0)) {
+ } else if(request.isPartSet("remove_finished_downloads_request") && !request.getPartAsStringFailsafe("remove_finished_downloads_request", 128).isEmpty()) {
// Remove all finished downloads
String identifier = "";
try {
@@ -372,7 +371,7 @@ public void handleMethodPOST(URI uri, HTTPRequest request, final ToadletContext
writePermanentRedirect(ctx, "Done", path());
return;
}
- else if(request.isPartSet("restart_request") && (request.getPartAsStringFailsafe("restart_request", 128).length() > 0)) {
+ else if(request.isPartSet("restart_request") && !request.getPartAsStringFailsafe("restart_request", 128).isEmpty()) {
boolean disableFilterData = request.isPartSet("disableFilterData");
@@ -392,22 +391,22 @@ else if(request.isPartSet("restart_request") && (request.getPartAsStringFailsafe
}
writePermanentRedirect(ctx, "Done", path());
return;
- } else if(request.isPartSet("panic") && (request.getPartAsStringFailsafe("panic", 128).length() > 0)) {
+ } else if(request.isPartSet("panic") && !request.getPartAsStringFailsafe("panic", 128).isEmpty()) {
if(SimpleToadletServer.noConfirmPanic) {
- core.node.killMasterKeysFile();
- core.node.panic();
+ core.getNode().killMasterKeysFile();
+ core.getNode().panic();
sendPanicingPage(ctx);
- core.node.finishPanic();
+ core.getNode().finishPanic();
return;
} else {
sendConfirmPanicPage(ctx);
return;
}
- } else if(request.isPartSet("confirmpanic") && (request.getPartAsStringFailsafe("confirmpanic", 128).length() > 0)) {
- core.node.killMasterKeysFile();
- core.node.panic();
+ } else if(request.isPartSet("confirmpanic") && !request.getPartAsStringFailsafe("confirmpanic", 128).isEmpty()) {
+ core.getNode().killMasterKeysFile();
+ core.getNode().panic();
sendPanicingPage(ctx);
- core.node.finishPanic();
+ core.getNode().finishPanic();
return;
} else if(request.isPartSet("download")) {
// Queue a download
@@ -456,7 +455,7 @@ else if(request.isPartSet("restart_request") && (request.getPartAsStringFailsafe
} else if(request.isPartSet("bulkDownloads")) {
String bulkDownloadsAsString = request.getPartAsStringFailsafe("bulkDownloads", 262144);
String[] keys = bulkDownloadsAsString.split("\n");
- if(("".equals(bulkDownloadsAsString)) || (keys.length < 1)) {
+ if(bulkDownloadsAsString.isEmpty() || (keys.length < 1)) {
writePermanentRedirect(ctx, "Done", path());
return;
}
@@ -481,7 +480,7 @@ else if(request.isPartSet("restart_request") && (request.getPartAsStringFailsafe
// trim leading/trailing space
currentKey = currentKey.trim();
- if (currentKey.length() == 0)
+ if (currentKey.isEmpty())
continue;
try {
@@ -497,8 +496,8 @@ else if(request.isPartSet("restart_request") && (request.getPartAsStringFailsafe
}
}
- boolean displayFailureBox = failure.size() > 0;
- boolean displaySuccessBox = success.size() > 0;
+ boolean displayFailureBox = !failure.isEmpty();
+ boolean displaySuccessBox = !success.isEmpty();
PageNode page = ctx.getPageMaker().getPageNode(l10n("downloadFiles"), ctx);
HTMLNode pageNode = page.outer;
@@ -540,7 +539,7 @@ else if(request.isPartSet("restart_request") && (request.getPartAsStringFailsafe
handleChangePriority(request, ctx, "_bottom");
return;
// FIXME factor out the next 3 items, they are very messy!
- } else if (request.getPartAsStringFailsafe("insert", 128).length() > 0) {
+ } else if (!request.getPartAsStringFailsafe("insert", 128).isEmpty()) {
final FreenetURI insertURI;
String keyType = request.getPartAsStringFailsafe("keytype", 10);
if ("CHK".equals(keyType)) {
@@ -567,21 +566,21 @@ else if(request.isPartSet("restart_request") && (request.getPartAsStringFailsafe
return;
}
final HTTPUploadedFile file = request.getUploadedFile("filename");
- if (file == null || file.getFilename().trim().length() == 0) {
+ if (file == null || file.getFilename().trim().isEmpty()) {
writeError(l10n("errorNoFileSelected"), l10n("errorNoFileSelectedU"), ctx, false, true);
return;
}
- final boolean compress = request.getPartAsStringFailsafe("compress", 128).length() > 0;
+ final boolean compress = !request.getPartAsStringFailsafe("compress", 128).isEmpty();
final String identifier = file.getFilename() + "-fred-" + System.currentTimeMillis();
final String compatibilityMode = request.getPartAsStringFailsafe("compatibilityMode", 100);
final CompatibilityMode cmode;
- if(compatibilityMode.equals(""))
+ if(compatibilityMode.isEmpty())
cmode = CompatibilityMode.COMPAT_DEFAULT.intern();
else
cmode = CompatibilityMode.valueOf(compatibilityMode).intern();
String s = request.getPartAsStringFailsafe("overrideSplitfileKey", 65);
final byte[] overrideSplitfileKey;
- if(s != null && !s.equals(""))
+ if(s != null && !s.isEmpty())
overrideSplitfileKey = HexUtil.hexToBytes(s);
else
overrideSplitfileKey = null;
@@ -591,11 +590,11 @@ else if(request.isPartSet("restart_request") && (request.getPartAsStringFailsafe
else
fnam = null;
/* copy bucket data */
- final RandomAccessBucket copiedBucket = core.persistentTempBucketFactory.makeBucket(file.getData().size());
+ final RandomAccessBucket copiedBucket = core.getPersistentTempBucketFactory().makeBucket(file.getData().size());
BucketTools.copy(file.getData(), copiedBucket);
final CountDownLatch done = new CountDownLatch(1);
try {
- core.clientLayerPersister.queue(new PersistentJob() {
+ core.getClientLayerPersister().queue(new PersistentJob() {
@Override
public String toString() {
@@ -607,7 +606,7 @@ public boolean run(ClientContext context) {
try {
final ClientPut clientPut;
try {
- clientPut = new ClientPut(fcp.getGlobalForeverClient(), insertURI, identifier, Integer.MAX_VALUE, null, RequestStarter.BULK_SPLITFILE_PRIORITY_CLASS, Persistence.FOREVER, null, false, !compress, -1, UploadFrom.DIRECT, null, file.getContentType(), copiedBucket, null, fnam, false, false, Node.FORK_ON_CACHEABLE_DEFAULT, HighLevelSimpleClientImpl.EXTRA_INSERTS_SINGLE_BLOCK, HighLevelSimpleClientImpl.EXTRA_INSERTS_SPLITFILE_HEADER, false, cmode, overrideSplitfileKey, false, fcp.core);
+ clientPut = new ClientPut(fcp.getGlobalForeverClient(), insertURI, identifier, Integer.MAX_VALUE, null, RequestStarter.BULK_SPLITFILE_PRIORITY_CLASS, Persistence.FOREVER, null, false, !compress, -1, UploadFrom.DIRECT, null, file.getContentType(), copiedBucket, null, fnam, false, false, Node.FORK_ON_CACHEABLE_DEFAULT, HighLevelSimpleClientImpl.EXTRA_INSERTS_SINGLE_BLOCK, HighLevelSimpleClientImpl.EXTRA_INSERTS_SPLITFILE_HEADER, false, cmode, overrideSplitfileKey, false, fcp.getCore());
if(clientPut != null)
try {
fcp.startBlocking(clientPut, context);
@@ -675,13 +674,13 @@ public boolean run(ClientContext context) {
final boolean compress = request.isPartSet("compress");
final String compatibilityMode = request.getPartAsStringFailsafe("compatibilityMode", 100);
final CompatibilityMode cmode;
- if(compatibilityMode.equals(""))
+ if(compatibilityMode.isEmpty())
cmode = CompatibilityMode.COMPAT_DEFAULT;
else
cmode = CompatibilityMode.valueOf(compatibilityMode);
String s = request.getPartAsStringFailsafe("overrideSplitfileKey", 65);
final byte[] overrideSplitfileKey;
- if(s != null && !s.equals(""))
+ if(s != null && !s.isEmpty())
overrideSplitfileKey = HexUtil.hexToBytes(s);
else
overrideSplitfileKey = null;
@@ -702,7 +701,7 @@ public boolean run(ClientContext context) {
target = file.getName();
final CountDownLatch done = new CountDownLatch(1);
try {
- core.clientLayerPersister.queue(new PersistentJob() {
+ core.getClientLayerPersister().queue(new PersistentJob() {
@Override
public String toString() {
@@ -714,7 +713,7 @@ public boolean run(ClientContext context) {
final ClientPut clientPut;
try {
try {
- clientPut = new ClientPut(fcp.getGlobalForeverClient(), furi, identifier, Integer.MAX_VALUE, null, RequestStarter.BULK_SPLITFILE_PRIORITY_CLASS, Persistence.FOREVER, null, false, !compress, -1, UploadFrom.DISK, file, contentType, new FileBucket(file, true, false, false, false), null, target, false, false, Node.FORK_ON_CACHEABLE_DEFAULT, HighLevelSimpleClientImpl.EXTRA_INSERTS_SINGLE_BLOCK, HighLevelSimpleClientImpl.EXTRA_INSERTS_SPLITFILE_HEADER, false, cmode, overrideSplitfileKey, false, fcp.core);
+ clientPut = new ClientPut(fcp.getGlobalForeverClient(), furi, identifier, Integer.MAX_VALUE, null, RequestStarter.BULK_SPLITFILE_PRIORITY_CLASS, Persistence.FOREVER, null, false, !compress, -1, UploadFrom.DISK, file, contentType, new FileBucket(file, true, false, false, false), null, target, false, false, Node.FORK_ON_CACHEABLE_DEFAULT, HighLevelSimpleClientImpl.EXTRA_INSERTS_SINGLE_BLOCK, HighLevelSimpleClientImpl.EXTRA_INSERTS_SPLITFILE_HEADER, false, cmode, overrideSplitfileKey, false, fcp.getCore());
if(logMINOR) Logger.minor(this, "Started global request to insert "+file+" to CHK@ as "+identifier);
if(clientPut != null)
try {
@@ -781,7 +780,7 @@ public boolean run(ClientContext context) {
final boolean compress = request.isPartSet("compress");
String s = request.getPartAsStringFailsafe("overrideSplitfileKey", 65);
final byte[] overrideSplitfileKey;
- if(s != null && !s.equals(""))
+ if(s != null && !s.isEmpty())
overrideSplitfileKey = HexUtil.hexToBytes(s);
else
overrideSplitfileKey = null;
@@ -797,7 +796,7 @@ public boolean run(ClientContext context) {
}
final CountDownLatch done = new CountDownLatch(1);
try {
- core.clientLayerPersister.queue(new PersistentJob() {
+ core.getClientLayerPersister().queue(new PersistentJob() {
@Override
public String toString() {
@@ -809,7 +808,7 @@ public boolean run(ClientContext context) {
ClientPutDir clientPutDir;
try {
try {
- clientPutDir = new ClientPutDir(fcp.getGlobalForeverClient(), furi, identifier, Integer.MAX_VALUE, RequestStarter.BULK_SPLITFILE_PRIORITY_CLASS, Persistence.FOREVER, null, false, !compress, -1, file, null, false, /* make include hidden files configurable? FIXME */ false, true, false, false, Node.FORK_ON_CACHEABLE_DEFAULT, HighLevelSimpleClientImpl.EXTRA_INSERTS_SINGLE_BLOCK, HighLevelSimpleClientImpl.EXTRA_INSERTS_SPLITFILE_HEADER, false, overrideSplitfileKey, fcp.core);
+ clientPutDir = new ClientPutDir(fcp.getGlobalForeverClient(), furi, identifier, Integer.MAX_VALUE, RequestStarter.BULK_SPLITFILE_PRIORITY_CLASS, Persistence.FOREVER, null, false, !compress, -1, file, null, false, /* make include hidden files configurable? FIXME */ false, true, false, false, Node.FORK_ON_CACHEABLE_DEFAULT, HighLevelSimpleClientImpl.EXTRA_INSERTS_SINGLE_BLOCK, HighLevelSimpleClientImpl.EXTRA_INSERTS_SPLITFILE_HEADER, false, overrideSplitfileKey, fcp.getCore());
if(logMINOR) Logger.minor(this, "Started global request to insert dir "+file+" to "+furi+" as "+identifier);
if(clientPutDir != null) {
try {
@@ -874,7 +873,7 @@ public boolean run(ClientContext context) {
for(String part : request.getParts()) {
if(!part.startsWith("identifier-")) continue;
String key = request.getPartAsStringFailsafe("key-"+part.substring("identifier-".length()), MAX_KEY_LENGTH);
- if(key == null || key.equals("")) {
+ if(key == null || key.isEmpty()) {
continue;
}
form.addChild("#", l10n("key") + ":");
@@ -891,18 +890,18 @@ public boolean run(ClientContext context) {
new String[]{"id", "name", "row", "cols"},
new String[]{"descB", "description", "3", "70"});
form.addChild("br");
- if (core.node.isFProxyJavascriptEnabled()) {
+ if (core.getNode().isFProxyJavascriptEnabled()) {
form.addChild("script", new String[] {"type", "src"}, new String[] {"text/javascript", "/static/js/checkall.js"});
}
HTMLNode peerTable = form.addChild("table", "class", "darknet_connections");
- if (core.node.isFProxyJavascriptEnabled()) {
+ if (core.getNode().isFProxyJavascriptEnabled()) {
HTMLNode headerRow = peerTable.addChild("tr");
headerRow.addChild("th").addChild("input", new String[] { "type", "onclick" }, new String[] { "checkbox", "checkAll(this, 'darknet_connections')" });
headerRow.addChild("th", l10n("recommendToFriends"));
} else {
peerTable.addChild("tr").addChild("th", "colspan", "2", l10n("recommendToFriends"));
}
- for(DarknetPeerNode peer : core.node.getDarknetConnections()) {
+ for(DarknetPeerNode peer : core.getNode().getDarknetConnections()) {
HTMLNode peerRow = peerTable.addChild("tr", "class", "darknet_connections_normal");
peerRow.addChild("td", "class", "peer-marker").addChild("input",
new String[] { "type", "name" },
@@ -931,7 +930,7 @@ public boolean run(ClientContext context) {
}
}
- for(DarknetPeerNode peer : core.node.getDarknetConnections()) {
+ for(DarknetPeerNode peer : core.getNode().getDarknetConnections()) {
if(request.isPartSet("node_" + peer.hashCode())) {
for(FreenetURI furi : uris)
peer.sendDownloadFeed(furi, description);
@@ -1021,7 +1020,7 @@ private void sendConfirmPanicPage(ToadletContext ctx) throws ToadletContextClose
private void sendPersistenceDisabledError(ToadletContext ctx) throws ToadletContextClosedException, IOException {
String title = l10n("awaitingPasswordTitle"+(uploads ? "Uploads" : "Downloads"));
- if(core.node.awaitingPassword()) {
+ if(core.getNode().awaitingPassword()) {
PageNode page = ctx.getPageMaker().getPageNode(title, ctx);
HTMLNode pageNode = page.outer;
HTMLNode contentNode = page.content;
@@ -1036,7 +1035,7 @@ private void sendPersistenceDisabledError(ToadletContext ctx) throws ToadletCont
return;
}
- if(core.node.isStopping())
+ if(core.getNode().isStopping())
sendErrorPage(ctx, 200,
l10n("shuttingDownTitle"),
l10n("shuttingDown"));
@@ -1045,7 +1044,7 @@ private void sendPersistenceDisabledError(ToadletContext ctx) throws ToadletCont
l10n("persistenceBrokenTitle"),
l10n("persistenceBroken",
new String[]{ "TEMPDIR", "DBFILE" },
- new String[]{ FileUtil.getCanonicalFile(core.getPersistentTempDir()).toString()+File.separator, core.node.getDatabasePath() }
+ new String[]{ FileUtil.getCanonicalFile(core.getPersistentTempDir()).toString()+File.separator, core.getNode().getDatabasePath() }
));
}
@@ -1073,7 +1072,7 @@ public void handleMethodGET(URI uri, final HTTPRequest request, final ToadletCon
throws ToadletContextClosedException, IOException, RedirectException {
// We ensure that we have a FCP server running
- if(!fcp.enabled){
+ if(!fcp.isEnabled()){
writeError(l10n("fcpIsMissing"), l10n("pleaseEnableFCP"), ctx, false, false);
return;
}
@@ -1088,7 +1087,7 @@ public void handleMethodGET(URI uri, final HTTPRequest request, final ToadletCon
boolean countRequests = false;
boolean listKeys = false;
- if (requestPath.length() > 0) {
+ if (!requestPath.isEmpty()) {
if(requestPath.equals("countRequests.html") || requestPath.equals("/countRequests.html")) {
countRequests = true;
} else if(requestPath.equals(KEY_LIST_LOCATION)) {
@@ -1113,7 +1112,7 @@ class OutputWrapper {
try {
RequestStatus[] reqs = fcp.getGlobalRequests();
MultiValueTable pageHeaders = new MultiValueTable();
- HTMLNode pageNode = handleGetInner(pageMaker, reqs, core.clientContext, request, ctx);
+ HTMLNode pageNode = handleGetInner(pageMaker, reqs, core.getClientContext(), request, ctx);
writeHTMLReply(ctx, 200, "OK", pageHeaders, pageNode.generate());
return;
} catch (PersistenceDisabledException e) {
@@ -1123,7 +1122,7 @@ class OutputWrapper {
}
try {
- core.clientContext.jobRunner.queue(new PersistentJob() {
+ core.getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public String toString() {
@@ -1136,9 +1135,9 @@ public boolean run(ClientContext context) {
String plainText = null;
try {
if(count) {
- long queued = core.requestStarters.chkFetchSchedulerBulk.countPersistentWaitingKeys() + core.requestStarters.chkFetchSchedulerRT.countPersistentWaitingKeys();
+ long queued = core.getRequestStarters().chkFetchSchedulerBulk.countPersistentWaitingKeys() + core.getRequestStarters().chkFetchSchedulerRT.countPersistentWaitingKeys();
Logger.minor(this, "Total waiting CHKs: "+queued);
- long reallyQueued = core.requestStarters.chkFetchSchedulerBulk.countQueuedRequests() + core.requestStarters.chkFetchSchedulerRT.countQueuedRequests();
+ long reallyQueued = core.getRequestStarters().chkFetchSchedulerBulk.countQueuedRequests() + core.getRequestStarters().chkFetchSchedulerRT.countQueuedRequests();
Logger.minor(this, "Total queued CHK requests (including transient): "+reallyQueued);
PageNode page = pageMaker.getPageNode(l10n("title"), ctx);
pageNode = page.outer;
@@ -1367,13 +1366,16 @@ public int compare(RequestStatus firstRequest, RequestStatus secondRequest) {
if(request.isParameterSet("sortBy")){
final String sortBy = request.getParam("sortBy");
- if(sortBy.equals("id")){
+ switch (sortBy) {
+ case "id":
result = firstRequest.getIdentifier().compareToIgnoreCase(secondRequest.getIdentifier());
if(result == 0)
result = firstRequest.getIdentifier().compareTo(secondRequest.getIdentifier());
- }else if(sortBy.equals("size")){
+ break;
+ case "size":
result = Fields.compare(firstRequest.getTotalBlocks(), secondRequest.getTotalBlocks());
- }else if(sortBy.equals("progress")){
+ break;
+ case "progress":
boolean firstFinalized = firstRequest.isTotalFinalized();
boolean secondFinalized = secondRequest.isTotalFinalized();
if(firstFinalized && !secondFinalized)
@@ -1385,14 +1387,19 @@ else if(secondFinalized && !firstFinalized)
double secondProgress = ((double)secondRequest.getFetchedBlocks()) / ((double)secondRequest.getMinBlocks());
result = Fields.compare(firstProgress, secondProgress);
}
- } else if (sortBy.equals("lastActivity")) {
+ break;
+ case "lastActivity":
result = Fields.compare(firstRequest.getLastSuccess(),
secondRequest.getLastSuccess());
- } else if (sortBy.equals("lastFailure")) {
+ break;
+ case "lastFailure":
result = Fields.compare(firstRequest.getLastFailure(),
secondRequest.getLastFailure());
- }else
+ break;
+ default:
isSet=false;
+ break;
+ }
}else
isSet=false;
@@ -1480,7 +1487,7 @@ else if(secondFinalized && !firstFinalized)
navigationContent.addChild("li").addChild("a", "href", "#failedDirUpload", l10n("failedDU", new String[]{ "size" }, new String[]{ String.valueOf(failedDirUpload.size()) }));
includeNavigationBar = true;
}
- if (failedUnknownMIMEType.size() > 0) {
+ if (!failedUnknownMIMEType.isEmpty()) {
String[] types = failedUnknownMIMEType.keySet().toArray(new String[failedUnknownMIMEType.size()]);
Arrays.sort(types);
for(String type : types) {
@@ -1488,7 +1495,7 @@ else if(secondFinalized && !firstFinalized)
navigationContent.addChild("li").addChild("a", "href", "#failedDownload-unknowntype-"+atype, l10n("failedDUnknownMIME", new String[]{ "size", "type" }, new String[]{ String.valueOf(failedUnknownMIMEType.get(type).size()), type }));
}
}
- if (failedBadMIMEType.size() > 0) {
+ if (!failedBadMIMEType.isEmpty()) {
String[] types = failedBadMIMEType.keySet().toArray(new String[failedBadMIMEType.size()]);
Arrays.sort(types);
for(String type : types) {
@@ -1995,7 +2002,7 @@ private HTMLNode createBulkDownloadForm(ToadletContext ctx, PageMaker pageMaker)
new String[] { "id", "name", "cols", "rows" },
new String[] { "bulkDownloads", "bulkDownloads", "120", "8" });
downloadForm.addChild("br");
- PHYSICAL_THREAT_LEVEL threatLevel = core.node.securityLevels.getPhysicalThreatLevel();
+ PHYSICAL_THREAT_LEVEL threatLevel = core.getNode().getSecurityLevels().getPhysicalThreatLevel();
//Force downloading to encrypted space if high/maximum threat level or if the user has disabled
//downloading to disk.
if(threatLevel == PHYSICAL_THREAT_LEVEL.HIGH || threatLevel == PHYSICAL_THREAT_LEVEL.MAXIMUM ||
@@ -2107,7 +2114,7 @@ private HTMLNode createRequestTable(PageMaker pageMaker, ToadletContext ctx, Lis
}
private HTMLNode createRequestTable(PageMaker pageMaker, ToadletContext ctx, List extends RequestStatus> requests, QueueColumn[] columns, String[] priorityClasses, boolean advancedModeEnabled, String id, String mimeType, QueueType queueType) {
- boolean hasFriends = core.node.getDarknetConnections().length > 0;
+ boolean hasFriends = core.getNode().getDarknetConnections().length > 0;
long now = System.currentTimeMillis();
HTMLNode formDiv = new HTMLNode("div", "class", "request-table-form");
@@ -2364,9 +2371,9 @@ public void run() {
private void loadCompletedIdentifiers() throws PersistenceDisabledException {
String dl = uploads ? "uploads" : "downloads";
- File completedIdentifiersList = core.node.userDir().file("completed.list."+dl);
- File completedIdentifiersListNew = core.node.userDir().file("completed.list."+dl+".bak");
- File oldCompletedIdentifiersList = core.node.userDir().file("completed.list");
+ File completedIdentifiersList = core.getNode().userDir().file("completed.list."+dl);
+ File completedIdentifiersListNew = core.getNode().userDir().file("completed.list."+dl+".bak");
+ File oldCompletedIdentifiersList = core.getNode().userDir().file("completed.list");
boolean migrated = false;
if(!readCompletedIdentifiers(completedIdentifiersList)) {
if(!readCompletedIdentifiers(completedIdentifiersListNew)) {
@@ -2376,7 +2383,7 @@ private void loadCompletedIdentifiers() throws PersistenceDisabledException {
} else
oldCompletedIdentifiersList.delete();
final boolean writeAnyway = migrated;
- core.clientContext.jobRunner.queue(new PersistentJob() {
+ core.getClientContext().jobRunner.queue(new PersistentJob() {
@Override
public String toString() {
@@ -2431,8 +2438,6 @@ private boolean readCompletedIdentifiers(File file) {
} catch (FileNotFoundException e) {
// Normal
return false;
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
} catch (IOException e) {
Logger.error(this, "Could not read completed identifiers list from "+file);
return false;
@@ -2443,14 +2448,14 @@ private void saveCompletedIdentifiers() {
FileOutputStream fos = null;
BufferedWriter bw = null;
String dl = uploads ? "uploads" : "downloads";
- File completedIdentifiersList = core.node.userDir().file("completed.list."+dl);
- File completedIdentifiersListNew = core.node.userDir().file("completed.list."+dl+".bak");
+ File completedIdentifiersList = core.getNode().userDir().file("completed.list."+dl);
+ File completedIdentifiersListNew = core.getNode().userDir().file("completed.list."+dl+".bak");
File temp;
try {
- temp = File.createTempFile("completed.list", ".tmp", core.node.getUserDir());
+ temp = File.createTempFile("completed.list", ".tmp", core.getNode().getUserDir());
temp.deleteOnExit();
fos = new FileOutputStream(temp);
- OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
+ OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
bw = new BufferedWriter(osw);
String[] identifiers;
synchronized(completedRequestIdentifiers) {
@@ -2513,7 +2518,7 @@ private void registerAlert(ClientRequest req) {
synchronized(completedGets) {
completedGets.put(identifier, event);
}
- core.alerts.register(event);
+ core.getAlerts().register(event);
} else if(req instanceof ClientPut) {
FreenetURI uri = ((ClientPut)req).getFinalURI();
if(uri == null) {
@@ -2525,7 +2530,7 @@ private void registerAlert(ClientRequest req) {
synchronized(completedPuts) {
completedPuts.put(identifier, event);
}
- core.alerts.register(event);
+ core.getAlerts().register(event);
} else if(req instanceof ClientPutDir) {
FreenetURI uri = ((ClientPutDir)req).getFinalURI();
if(uri == null) {
@@ -2538,7 +2543,7 @@ private void registerAlert(ClientRequest req) {
synchronized(completedPutDirs) {
completedPutDirs.put(identifier, event);
}
- core.alerts.register(event);
+ core.getAlerts().register(event);
}
}
diff --git a/src/freenet/clients/http/ReceivedCookie.java b/src/freenet/clients/http/ReceivedCookie.java
index 1749c621e44..1b160fd11f7 100644
--- a/src/freenet/clients/http/ReceivedCookie.java
+++ b/src/freenet/clients/http/ReceivedCookie.java
@@ -105,7 +105,7 @@ protected static ArrayList parseHeader(String httpHeader) throws
key = new String(header, keyBeginIndex, keyEndIndex - keyBeginIndex).toLowerCase();
- if(key.length() == 0)
+ if(key.isEmpty())
throw new ParseException("Invalid cookie: Contains an empty key: " + httpHeader, i);
// We're done parsing the key, continue to the next character.
diff --git a/src/freenet/clients/http/SecurityLevelsToadlet.java b/src/freenet/clients/http/SecurityLevelsToadlet.java
index 3f8d7f69651..418acc6a35a 100644
--- a/src/freenet/clients/http/SecurityLevelsToadlet.java
+++ b/src/freenet/clients/http/SecurityLevelsToadlet.java
@@ -74,9 +74,9 @@ public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) t
String networkThreatLevel = request.getPartAsStringFailsafe(configName, 128);
NETWORK_THREAT_LEVEL newThreatLevel = SecurityLevels.parseNetworkThreatLevel(networkThreatLevel);
if(newThreatLevel != null) {
- if(newThreatLevel != node.securityLevels.getNetworkThreatLevel()) {
+ if(newThreatLevel != node.getSecurityLevels().getNetworkThreatLevel()) {
if(!request.isPartSet(confirm) && !request.isPartSet(tryConfirm)) {
- HTMLNode warning = node.securityLevels.getConfirmWarning(newThreatLevel, confirm);
+ HTMLNode warning = node.getSecurityLevels().getConfirmWarning(newThreatLevel, confirm);
if(warning != null) {
PageNode page = ctx.getPageMaker().getPageNode(NodeL10n.getBase().getString("ConfigToadlet.fullTitle"), ctx);
pageNode = page.outer;
@@ -93,12 +93,12 @@ public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) t
infoboxContent.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", tryConfirm, "on" });
} else {
// Apply immediately, no confirm needed.
- node.securityLevels.setThreatLevel(newThreatLevel);
+ node.getSecurityLevels().setThreatLevel(newThreatLevel);
changedAnything = true;
}
} else if(request.isPartSet(confirm)) {
// Apply immediately, user confirmed it.
- node.securityLevels.setThreatLevel(newThreatLevel);
+ node.getSecurityLevels().setThreatLevel(newThreatLevel);
changedAnything = true;
}
}
@@ -109,8 +109,8 @@ public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) t
tryConfirm = "security-levels.physicalThreatLevel.tryConfirm";
String physicalThreatLevel = request.getPartAsStringFailsafe(configName, 128);
PHYSICAL_THREAT_LEVEL newPhysicalLevel = SecurityLevels.parsePhysicalThreatLevel(physicalThreatLevel);
- PHYSICAL_THREAT_LEVEL oldPhysicalLevel = core.node.securityLevels.getPhysicalThreatLevel();
- if(logMINOR) Logger.minor(this, "New physical threat level: "+newPhysicalLevel+" old = "+node.securityLevels.getPhysicalThreatLevel());
+ PHYSICAL_THREAT_LEVEL oldPhysicalLevel = core.getNode().getSecurityLevels().getPhysicalThreatLevel();
+ if(logMINOR) Logger.minor(this, "New physical threat level: "+newPhysicalLevel+" old = "+node.getSecurityLevels().getPhysicalThreatLevel());
if(newPhysicalLevel != null) {
if(newPhysicalLevel == oldPhysicalLevel && newPhysicalLevel == PHYSICAL_THREAT_LEVEL.HIGH) {
String password = request.getPartAsStringFailsafe("masterPassword", MAX_PASSWORD_LENGTH);
@@ -118,7 +118,7 @@ public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) t
String confirmPassword = request.getPartAsStringFailsafe("confirmMasterPassword", MAX_PASSWORD_LENGTH);
if (!oldPassword.isEmpty() && !confirmPassword.isEmpty() && !password.isEmpty() && password.equals(confirmPassword)) {
try {
- core.node.changeMasterPassword(oldPassword, password, false);
+ core.getNode().changeMasterPassword(oldPassword, password, false);
} catch (MasterKeysWrongPasswordException e) {
sendChangePasswordForm(ctx, true, false, newPhysicalLevel.name());
return;
@@ -142,16 +142,16 @@ public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) t
}
if(newPhysicalLevel != oldPhysicalLevel) {
// No confirmation for changes to physical threat level.
- if(newPhysicalLevel == PHYSICAL_THREAT_LEVEL.HIGH && node.securityLevels.getPhysicalThreatLevel() != newPhysicalLevel) {
+ if(newPhysicalLevel == PHYSICAL_THREAT_LEVEL.HIGH && node.getSecurityLevels().getPhysicalThreatLevel() != newPhysicalLevel) {
// Check for password
String password = request.getPartAsStringFailsafe("masterPassword", MAX_PASSWORD_LENGTH);
String confirmPassword = request.getPartAsStringFailsafe("confirmMasterPassword", MAX_PASSWORD_LENGTH);
if (!password.isEmpty() && !confirmPassword.isEmpty() && password.equals(confirmPassword)) {
try {
if(oldPhysicalLevel == PHYSICAL_THREAT_LEVEL.NORMAL || oldPhysicalLevel == PHYSICAL_THREAT_LEVEL.LOW)
- core.node.changeMasterPassword("", password, false);
+ core.getNode().changeMasterPassword("", password, false);
else
- core.node.setMasterPassword(password, false);
+ core.getNode().setMasterPassword(password, false);
} catch (AlreadySetPasswordException e) {
sendChangePasswordForm(ctx, false, false, newPhysicalLevel.name());
return;
@@ -194,9 +194,9 @@ public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) t
if (!password.isEmpty()) {
// This is actually the OLD password ...
try {
- core.node.changeMasterPassword(password, "", false);
+ core.getNode().changeMasterPassword(password, "", false);
} catch (IOException e) {
- if(!core.node.getMasterPasswordFile().exists()) {
+ if(!core.getNode().getMasterPasswordFile().exists()) {
// Ok.
System.out.println("Master password file no longer exists, assuming this is deliberate");
} else {
@@ -243,7 +243,7 @@ public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) t
core.storeConfig();
return;
}
- } else if(core.node.getMasterPasswordFile().exists()) {
+ } else if(core.getNode().getMasterPasswordFile().exists()) {
// We need the old password
PageNode page = ctx.getPageMaker().getPageNode(l10nSec("passwordForDecryptTitle"), ctx);
pageNode = page.outer;
@@ -271,13 +271,13 @@ public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) t
}
if(newPhysicalLevel == PHYSICAL_THREAT_LEVEL.MAXIMUM) {
try {
- core.node.killMasterKeysFile();
+ core.getNode().killMasterKeysFile();
} catch (IOException e) {
sendCantDeleteMasterKeysFile(ctx, newPhysicalLevel.name());
return;
}
}
- node.securityLevels.setThreatLevel(newPhysicalLevel);
+ node.getSecurityLevels().setThreatLevel(newPhysicalLevel);
changedAnything = true;
}
}
@@ -481,7 +481,7 @@ private void drawSecurityLevelsPage(HTMLNode contentNode, ToadletContext ctx) {
HTMLNode seclevelGroup = ul.addChild("li");
seclevelGroup.addChild("#", l10nSec("networkThreatLevel.opennetIntro"));
- NETWORK_THREAT_LEVEL networkLevel = node.securityLevels.getNetworkThreatLevel();
+ NETWORK_THREAT_LEVEL networkLevel = node.getSecurityLevels().getNetworkThreatLevel();
HTMLNode p = seclevelGroup.addChild("p");
p.addChild("b", l10nSec("networkThreatLevel.opennetLabel"));
@@ -561,7 +561,7 @@ private void drawSecurityLevelsPage(HTMLNode contentNode, ToadletContext ctx) {
swapWarning.addChild("#", " " + WizardL10n.l10nSec("physicalThreatLevelSwapfileWindows"));
}
- PHYSICAL_THREAT_LEVEL physicalLevel = node.securityLevels.getPhysicalThreatLevel();
+ PHYSICAL_THREAT_LEVEL physicalLevel = node.getSecurityLevels().getPhysicalThreatLevel();
controlName = "security-levels.physicalThreatLevel";
for(PHYSICAL_THREAT_LEVEL level : PHYSICAL_THREAT_LEVEL.values()) {
diff --git a/src/freenet/clients/http/SessionManager.java b/src/freenet/clients/http/SessionManager.java
index 78029af6c15..67d2d776dd6 100644
--- a/src/freenet/clients/http/SessionManager.java
+++ b/src/freenet/clients/http/SessionManager.java
@@ -16,7 +16,6 @@
import java.util.Set;
import java.util.UUID;
-import freenet.support.CurrentTimeUTC;
import freenet.support.LRUMap;
import freenet.support.Logger;
import freenet.support.StringValidityChecker;
@@ -95,7 +94,7 @@ public SessionManager(URI myCookiePath) {
* @param myCookieNamespace The name of the client application which uses this cookie. Must not be empty. Must be latin letters and numbers only.
*/
public SessionManager(String myCookieNamespace) {
- if(myCookieNamespace.length() == 0)
+ if(myCookieNamespace.isEmpty())
throw new IllegalArgumentException("You must specify a cookie namespace or use the constructor " +
"which allows specification of a cookie path.");
@@ -252,7 +251,7 @@ public String getCookieNamespace() {
public synchronized Session createSession(String userID, ToadletContext context) {
// We must synchronize around the fetching of the time and mSessionsByID.push() because mSessionsByID is no sorting data structure: It's a plain
// LRUMap so to ensure that it stays sorted the operation "getTime(); push();" must be atomic.
- long time = CurrentTimeUTC.getInMillis();
+ long time = System.currentTimeMillis();
removeExpiredSessions(time);
@@ -279,7 +278,7 @@ public synchronized boolean sessionExists(ToadletContext context) {
if(sessionID == null)
return false;
- removeExpiredSessions(CurrentTimeUTC.getInMillis());
+ removeExpiredSessions(System.currentTimeMillis());
return mSessionsByID.containsKey(sessionID);
}
@@ -299,7 +298,7 @@ public synchronized Session useSession(ToadletContext context) {
// We must synchronize around the fetching of the time and mSessionsByID.push() because mSessionsByID is no sorting data structure: It's a plain
// LRUMap so to ensure that it stays sorted the operation "getTime(); push();" must be atomic.
- long time = CurrentTimeUTC.getInMillis();
+ long time = System.currentTimeMillis();
removeExpiredSessions(time);
diff --git a/src/freenet/clients/http/SimpleToadletServer.java b/src/freenet/clients/http/SimpleToadletServer.java
index 3e294279750..fc1696c35db 100644
--- a/src/freenet/clients/http/SimpleToadletServer.java
+++ b/src/freenet/clients/http/SimpleToadletServer.java
@@ -124,10 +124,15 @@ public ToadletElement(Toadlet t2, String urlPrefix, String menu, String name) {
private int fproxyConnections;
private boolean finishedStartup;
-
- /** The PushDataManager handles all the pushing tasks*/
- public PushDataManager pushDataManager;
-
+
+ /**
+ * The PushDataManager handles all the pushing tasks
+ * @deprecated Use {@link #getPushDataManager()} instead of accessing this directly.
+ */
+ @Deprecated
+ /* It’s not the field that is deprecated but accessing it directly is. */
+ public PushDataManager pushDataManager;
+
/** The IntervalPusherManager handles interval pushing*/
public IntervalPusherManager intervalPushManager;
@@ -258,8 +263,8 @@ public void set(String CSSName) throws InvalidConfigValueException {
cssTheme = THEME.themeFromName(CSSName);
pageMaker.setTheme(cssTheme);
NodeClientCore core = SimpleToadletServer.this.core;
- if (core.node.pluginManager != null)
- core.node.pluginManager.setFProxyTheme(cssTheme);
+ if (core.getNode().getPluginManager() != null)
+ core.getNode().getPluginManager().setFProxyTheme(cssTheme);
fetchKeyBoxAboveBookmarks = cssTheme.fetchKeyBoxAboveBookmarks;
}
@@ -278,7 +283,7 @@ public String get() {
public void set(String val) throws InvalidConfigValueException {
NodeClientCore core = SimpleToadletServer.this.core;
if(core == null) return;
- if(val.equals(get()) || val.equals(""))
+ if(val.equals(get()) || val.isEmpty())
cssOverride = null;
else {
File tmp = new File(val.trim());
@@ -415,11 +420,11 @@ public void set(String val) throws InvalidConfigValueException,
refilterPolicy = REFILTER_POLICY.valueOf(val);
}
- };
+ }
public void createFproxy() {
NodeClientCore core = this.core;
- Node node = core.node;
+ Node node = core.getNode();
synchronized(this) {
if(haveCalledFProxy) return;
haveCalledFProxy = true;
@@ -429,7 +434,7 @@ public void createFproxy() {
intervalPushManager=new IntervalPusherManager(getTicker(), pushDataManager);
bookmarkManager = new BookmarkManager(core, publicGatewayMode());
try {
- FProxyToadlet.maybeCreateFProxyEtc(core, node, node.config, this);
+ FProxyToadlet.maybeCreateFProxyEtc(core, node, node.getConfig(), this);
} catch (IOException e) {
Logger.error(this, "Could not start fproxy: "+e, e);
System.err.println("Could not start fproxy:");
@@ -887,7 +892,7 @@ public void start() {
}
public void finishStart() {
- core.node.securityLevels.addNetworkThreatLevelListener(new SecurityLevelListener() {
+ core.getNode().getSecurityLevels().addNetworkThreatLevelListener(new SecurityLevelListener() {
@Override
public void onChange(NETWORK_THREAT_LEVEL oldLevel,
@@ -903,7 +908,7 @@ public void onChange(NETWORK_THREAT_LEVEL oldLevel,
}
});
- core.node.securityLevels.addPhysicalThreatLevelListener(new SecurityLevelListener () {
+ core.getNode().getSecurityLevels().addPhysicalThreatLevelListener(new SecurityLevelListener () {
@Override
public void onChange(PHYSICAL_THREAT_LEVEL oldLevel, PHYSICAL_THREAT_LEVEL newLevel) {
@@ -981,7 +986,7 @@ public Toadlet findToadlet(URI uri) throws PermanentRedirectException {
// Show the wizard until dismissed by the user (See bug #2624)
NodeClientCore core = this.core;
- if(core != null && core.node != null && !fproxyHasCompletedWizard) {
+ if(core != null && core.getNode() != null && !fproxyHasCompletedWizard) {
//If the user has not completed the wizard, only allow access to the wizard and static
//resources. Anything else redirects to the first page of the wizard.
if (!(path.startsWith(FirstTimeWizardToadlet.TOADLET_URL) ||
@@ -999,7 +1004,7 @@ public Toadlet findToadlet(URI uri) throws PermanentRedirectException {
for(ToadletElement te: toadlets) {
if(path.startsWith(te.prefix))
return te.t;
- if(te.prefix.length() > 0 && te.prefix.charAt(te.prefix.length()-1) == '/') {
+ if(!te.prefix.isEmpty() && te.prefix.charAt(te.prefix.length()-1) == '/') {
if(path.equals(te.prefix.substring(0, te.prefix.length()-1))) {
URI newURI;
try {
@@ -1097,7 +1102,7 @@ public THEME getTheme() {
public UserAlertManager getUserAlertManager() {
NodeClientCore core = this.core;
if(core == null) return null;
- return core.alerts;
+ return core.getAlerts();
}
public void setCSSName(THEME theme) {
@@ -1120,7 +1125,7 @@ public void setAdvancedMode(boolean enabled) {
if(advancedModeEnabled == enabled) return;
advancedModeEnabled = enabled;
}
- core.node.config.store();
+ core.getNode().getConfig().store();
}
@Override
@@ -1144,7 +1149,7 @@ public synchronized void enableFProxyWebPushing(boolean b){
@Override
public String getFormPassword() {
if(core == null) return "";
- return core.formPassword;
+ return core.getFormPassword();
}
@Override
@@ -1241,7 +1246,7 @@ public PageMaker getPageMaker() {
}
public Ticker getTicker(){
- return core.node.getTicker();
+ return core.getNode().getTicker();
}
public NodeClientCore getCore(){
@@ -1316,4 +1321,8 @@ public long generateUniqueID() {
return random.nextLong();
}
+ public PushDataManager getPushDataManager() {
+ return pushDataManager;
+ }
+
}
diff --git a/src/freenet/clients/http/StaticToadlet.java b/src/freenet/clients/http/StaticToadlet.java
index 7cde7ee8c34..d2546b953c8 100644
--- a/src/freenet/clients/http/StaticToadlet.java
+++ b/src/freenet/clients/http/StaticToadlet.java
@@ -43,7 +43,7 @@ public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx) th
}
// be very strict about what characters we allow in the path, since
- if (!path.matches("^[A-Za-z0-9\\._\\/\\-]*$") || (path.indexOf("..") != -1)) {
+ if (!path.matches("^[A-Za-z0-9\\._\\/\\-]*$") || path.contains("..")) {
this.sendErrorPage(ctx, 404, l10n("pathNotFoundTitle"), l10n("pathInvalidChars"));
return;
}
diff --git a/src/freenet/clients/http/StatisticsToadlet.java b/src/freenet/clients/http/StatisticsToadlet.java
index eb82ad4ed6e..44eda7a2849 100644
--- a/src/freenet/clients/http/StatisticsToadlet.java
+++ b/src/freenet/clients/http/StatisticsToadlet.java
@@ -79,8 +79,8 @@ protected StatisticsToadlet(Node n, NodeClientCore core, HighLevelSimpleClient c
super(client);
this.node = n;
this.core = core;
- stats = node.nodeStats;
- peers = node.peers;
+ stats = node.getNodeStats();
+ peers = node.getPeers();
}
/**
@@ -122,18 +122,18 @@ public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx) th
if(!ctx.checkFullAccess(this))
return;
- final SubConfig nodeConfig = node.config.get("node");
+ final SubConfig nodeConfig = node.getConfig().get("node");
final String requestPath = request.getPath().substring(path().length());
- if (requestPath.length() > 0) {
+ if (!requestPath.isEmpty()) {
if(requestPath.equals("requesters.html") || requestPath.equals("/requesters.html")) {
showRequesters(request, ctx);
return;
}
}
- node.clientCore.bandwidthStatsPutter.updateData(node);
+ node.getClientCore().getBandwidthStatsPutter().updateData(node);
HTMLNode pageNode;
@@ -179,7 +179,7 @@ public int compare(PeerNodeStatus firstNode, PeerNodeStatus secondNode) {
// FIXME! We need some nice images
final long now = System.currentTimeMillis();
double myLocation = node.getLocation();
- final long nodeUptimeSeconds = (now - node.startupTime) / 1000;
+ final long nodeUptimeSeconds = (now - node.getStartupTime()) / 1000;
if(ctx.isAllowedFullAccess())
contentNode.addChild(ctx.getAlertManager().createSummary());
@@ -234,8 +234,11 @@ public int compare(PeerNodeStatus firstNode, PeerNodeStatus secondNode) {
drawLoadBalancingBox(loadStatsInfobox, true);
- HTMLNode newLoadManagementBox = nextTableCell.addChild("div", "class", "infobox");
- drawNewLoadManagementBox(newLoadManagementBox);
+ // New load management statistics
+ if(stats.enableNewLoadManagement(true) || stats.enableNewLoadManagement(false)) {
+ HTMLNode newLoadManagementBox = nextTableCell.addChild("div", "class", "infobox");
+ drawNewLoadManagementBox(newLoadManagementBox);
+ }
// Psuccess box
HTMLNode successRateBox = nextTableCell.addChild("div", "class", "infobox");
@@ -271,7 +274,7 @@ public int compare(PeerNodeStatus firstNode, PeerNodeStatus secondNode) {
/* node status overview box */
if(advancedMode) {
HTMLNode overviewInfobox = nextTableCell.addChild("div", "class", "infobox");
- drawOverviewBox(overviewInfobox, nodeUptimeSeconds, node.clientCore.bandwidthStatsPutter.getLatestUptimeData().totalUptime, now, swaps, noSwaps);
+ drawOverviewBox(overviewInfobox, nodeUptimeSeconds, node.getClientCore().getBandwidthStatsPutter().getLatestUptimeData().totalUptime, now, swaps, noSwaps);
}
// Peer statistics box
@@ -543,7 +546,7 @@ private void drawLoadBalancingBox(HTMLNode loadStatsInfobox, boolean realTime) {
loadStatsInfobox.addChild("div", "class", "infobox-header", "Load limiting "+(realTime ? "RealTime" : "Bulk"));
HTMLNode loadStatsContent = loadStatsInfobox.addChild("div", "class", "infobox-content");
- RequestStarterGroup starters = core.requestStarters;
+ RequestStarterGroup starters = core.getRequestStarters();
double window = starters.getWindow(realTime);
double realWindow = starters.getRealWindow(realTime);
HTMLNode loadStatsList = loadStatsContent.addChild("ul");
@@ -560,12 +563,12 @@ private void drawLoadBalancingBox(HTMLNode loadStatsInfobox, boolean realTime) {
private void drawNewLoadManagementBox(HTMLNode infobox) {
infobox.addChild("div", "class", "infobox-header", l10n("newLoadManagementTitle"));
HTMLNode content = infobox.addChild("div", "class", "infobox-content");
- node.nodeStats.drawNewLoadManagementDelayTimes(content);
+ node.getNodeStats().drawNewLoadManagementDelayTimes(content);
}
private void drawRejectReasonsBox(HTMLNode nextTableCell, boolean local) {
HTMLNode rejectReasonsTable = new HTMLNode("table");
- NodeStats stats = node.nodeStats;
+ NodeStats stats = node.getNodeStats();
boolean success = local ? stats.getLocalRejectReasonsTable(rejectReasonsTable) :
stats.getRejectReasonsTable(rejectReasonsTable);
if(!success)
@@ -753,7 +756,7 @@ private void drawStoreSizeBox(HTMLNode storeSizeInfobox, double loc, long nodeUp
// FIXME this is not necessarily the same as the datastore's uptime if we've switched.
// Ideally we'd track uptime there too.
totalUptimeSeconds =
- node.clientCore.bandwidthStatsPutter.getLatestUptimeData().totalUptime;
+ node.getClientCore().getBandwidthStatsPutter().getLatestUptimeData().totalUptime;
} catch (StatsNotAvailableException e) {
totalAccess = null;
}
@@ -1055,33 +1058,33 @@ private void drawActivityBox(HTMLNode activityInfobox, boolean advancedModeEnabl
if (advancedModeEnabled && activityList != null) {
if (numARKFetchers > 0)
activityList.addChild("li", "ARK\u00a0Fetch\u00a0Requests:\u00a0" + numARKFetchers);
- activityList.addChild("li", "BackgroundFetcherByUSKSize:\u00a0" + node.clientCore.uskManager.getBackgroundFetcherByUSKSize());
- activityList.addChild("li", "temporaryBackgroundFetchersLRUSize:\u00a0" + node.clientCore.uskManager.getTemporaryBackgroundFetchersLRU());
- activityList.addChild("li", "outputBandwidthLiabilityUsage:\u00a0" + this.fix3p1pct.format(node.nodeStats.getBandwidthLiabilityUsage()));
+ activityList.addChild("li", "BackgroundFetcherByUSKSize:\u00a0" + node.getClientCore().getUskManager().getBackgroundFetcherByUSKSize());
+ activityList.addChild("li", "temporaryBackgroundFetchersLRUSize:\u00a0" + node.getClientCore().getUskManager().getTemporaryBackgroundFetchersLRU());
+ activityList.addChild("li", "outputBandwidthLiabilityUsage:\u00a0" + this.fix3p1pct.format(node.getNodeStats().getBandwidthLiabilityUsage()));
}
}
static void drawBandwidth(HTMLNode activityList, Node node, long nodeUptimeSeconds, boolean isAdvancedModeEnabled) {
- long[] total = node.collector.getTotalIO();
+ long[] total = node.getCollector().getTotalIO();
if(total[0] == 0 || total[1] == 0)
return;
long total_output_rate = (total[0]) / nodeUptimeSeconds;
long total_input_rate = (total[1]) / nodeUptimeSeconds;
long totalPayload = node.getTotalPayloadSent();
long total_payload_rate = totalPayload / nodeUptimeSeconds;
- if(node.clientCore == null) throw new NullPointerException();
- BandwidthStatsContainer stats = node.clientCore.bandwidthStatsPutter.getLatestBWData();
+ if(node.getClientCore() == null) throw new NullPointerException();
+ BandwidthStatsContainer stats = node.getClientCore().getBandwidthStatsPutter().getLatestBWData();
if(stats == null) throw new NullPointerException();
long overall_total_out = stats.totalBytesOut;
long overall_total_in = stats.totalBytesIn;
int percent = (int) (100 * totalPayload / total[0]);
- long[] rate = node.nodeStats.getNodeIOStats();
+ long[] rate = node.getNodeStats().getNodeIOStats();
long delta = (rate[5] - rate[2]) / 1000;
if(delta > 0) {
long output_rate = (rate[3] - rate[0]) / delta;
long input_rate = (rate[4] - rate[1]) / delta;
- SubConfig nodeConfig = node.config.get("node");
+ SubConfig nodeConfig = node.getConfig().get("node");
int outputBandwidthLimit = nodeConfig.getInt("outputBandwidthLimit");
int inputBandwidthLimit = nodeConfig.getInt("inputBandwidthLimit");
if(inputBandwidthLimit == -1) {
@@ -1096,30 +1099,30 @@ static void drawBandwidth(HTMLNode activityList, Node node, long nodeUptimeSecon
activityList.addChild("li", l10n("totalInput", new String[] { "total" }, new String[] { SizeUtil.formatSize(overall_total_in, true) }));
activityList.addChild("li", l10n("totalOutput", new String[] { "total" }, new String[] { SizeUtil.formatSize(overall_total_out, true) } ));
if(isAdvancedModeEnabled) {
- long totalBytesSentCHKRequests = node.nodeStats.getCHKRequestTotalBytesSent();
- long totalBytesSentSSKRequests = node.nodeStats.getSSKRequestTotalBytesSent();
- long totalBytesSentCHKInserts = node.nodeStats.getCHKInsertTotalBytesSent();
- long totalBytesSentSSKInserts = node.nodeStats.getSSKInsertTotalBytesSent();
- long totalBytesSentOfferedKeys = node.nodeStats.getOfferedKeysTotalBytesSent();
- long totalBytesSendOffers = node.nodeStats.getOffersSentBytesSent();
- long totalBytesSentSwapOutput = node.nodeStats.getSwappingTotalBytesSent();
- long totalBytesSentAuth = node.nodeStats.getTotalAuthBytesSent();
- long totalBytesSentAckOnly = node.nodeStats.getNotificationOnlyPacketsSentBytes();
- long totalBytesSentResends = node.nodeStats.getResendBytesSent();
- long totalBytesSentUOM = node.nodeStats.getUOMBytesSent();
- long totalBytesSentAnnounce = node.nodeStats.getAnnounceBytesSent();
- long totalBytesSentAnnouncePayload = node.nodeStats.getAnnounceBytesPayloadSent();
- long totalBytesSentRoutingStatus = node.nodeStats.getRoutingStatusBytes();
- long totalBytesSentNetworkColoring = node.nodeStats.getNetworkColoringSentBytes();
- long totalBytesSentPing = node.nodeStats.getPingSentBytes();
- long totalBytesSentProbeRequest = node.nodeStats.getProbeRequestSentBytes();
- long totalBytesSentRouted = node.nodeStats.getRoutedMessageSentBytes();
- long totalBytesSentDisconn = node.nodeStats.getDisconnBytesSent();
- long totalBytesSentInitial = node.nodeStats.getInitialMessagesBytesSent();
- long totalBytesSentChangedIP = node.nodeStats.getChangedIPBytesSent();
- long totalBytesSentNodeToNode = node.nodeStats.getNodeToNodeBytesSent();
- long totalBytesSentAllocationNotices = node.nodeStats.getAllocationNoticesBytesSent();
- long totalBytesSentFOAF = node.nodeStats.getFOAFBytesSent();
+ long totalBytesSentCHKRequests = node.getNodeStats().getCHKRequestTotalBytesSent();
+ long totalBytesSentSSKRequests = node.getNodeStats().getSSKRequestTotalBytesSent();
+ long totalBytesSentCHKInserts = node.getNodeStats().getCHKInsertTotalBytesSent();
+ long totalBytesSentSSKInserts = node.getNodeStats().getSSKInsertTotalBytesSent();
+ long totalBytesSentOfferedKeys = node.getNodeStats().getOfferedKeysTotalBytesSent();
+ long totalBytesSendOffers = node.getNodeStats().getOffersSentBytesSent();
+ long totalBytesSentSwapOutput = node.getNodeStats().getSwappingTotalBytesSent();
+ long totalBytesSentAuth = node.getNodeStats().getTotalAuthBytesSent();
+ long totalBytesSentAckOnly = node.getNodeStats().getNotificationOnlyPacketsSentBytes();
+ long totalBytesSentResends = node.getNodeStats().getResendBytesSent();
+ long totalBytesSentUOM = node.getNodeStats().getUOMBytesSent();
+ long totalBytesSentAnnounce = node.getNodeStats().getAnnounceBytesSent();
+ long totalBytesSentAnnouncePayload = node.getNodeStats().getAnnounceBytesPayloadSent();
+ long totalBytesSentRoutingStatus = node.getNodeStats().getRoutingStatusBytes();
+ long totalBytesSentNetworkColoring = node.getNodeStats().getNetworkColoringSentBytes();
+ long totalBytesSentPing = node.getNodeStats().getPingSentBytes();
+ long totalBytesSentProbeRequest = node.getNodeStats().getProbeRequestSentBytes();
+ long totalBytesSentRouted = node.getNodeStats().getRoutedMessageSentBytes();
+ long totalBytesSentDisconn = node.getNodeStats().getDisconnBytesSent();
+ long totalBytesSentInitial = node.getNodeStats().getInitialMessagesBytesSent();
+ long totalBytesSentChangedIP = node.getNodeStats().getChangedIPBytesSent();
+ long totalBytesSentNodeToNode = node.getNodeStats().getNodeToNodeBytesSent();
+ long totalBytesSentAllocationNotices = node.getNodeStats().getAllocationNoticesBytesSent();
+ long totalBytesSentFOAF = node.getNodeStats().getFOAFBytesSent();
long totalBytesSentRemaining = total[0] -
(totalPayload + totalBytesSentCHKRequests + totalBytesSentSSKRequests +
totalBytesSentCHKInserts + totalBytesSentSSKInserts +
@@ -1145,14 +1148,14 @@ static void drawBandwidth(HTMLNode activityList, Node node, long nodeUptimeSecon
activityList.addChild("li", l10n("foafBytes", "total", SizeUtil.formatSize(totalBytesSentFOAF, true)));
activityList.addChild("li", l10n("unaccountedBytes", new String[] { "total", "percent" },
new String[] { SizeUtil.formatSize(totalBytesSentRemaining, true), Integer.toString((int)(totalBytesSentRemaining*100 / total[0])) }));
- double sentOverheadPerSecond = node.nodeStats.getSentOverheadPerSecond();
+ double sentOverheadPerSecond = node.getNodeStats().getSentOverheadPerSecond();
activityList.addChild("li", l10n("totalOverhead", new String[] { "rate", "percent" },
new String[] { SizeUtil.formatSize((long)sentOverheadPerSecond), Integer.toString((int)((100 * sentOverheadPerSecond) / total_output_rate)) }));
}
}
static HTMLNode drawActivity(HTMLNode activityInfoboxContent, Node node) {
- RequestTracker tracker = node.tracker;
+ RequestTracker tracker = node.getTracker();
int numLocalCHKInserts = tracker.getNumLocalCHKInserts();
int numRemoteCHKInserts = tracker.getNumRemoteCHKInserts();
int numLocalSSKInserts = tracker.getNumLocalSSKInserts();
@@ -1277,8 +1280,8 @@ private void drawOverviewBox(HTMLNode overviewInfobox, long nodeUptimeSeconds, l
overviewList.addChild("li", "pInstantRejectRequestRT:\u00a0" + fix3p1pct.format(stats.pRejectIncomingInstantlyCHKRequestRT())+" (CHK) "+fix3p1pct.format(stats.pRejectIncomingInstantlySSKRequestRT())+" (SSK)");
overviewList.addChild("li", "pInstantRejectInsertRT:\u00a0" + fix3p1pct.format(stats.pRejectIncomingInstantlyCHKInsertRT())+" (CHK) "+fix3p1pct.format(stats.pRejectIncomingInstantlySSKInsertRT())+" (SSK)");
overviewList.addChild("li", "unclaimedFIFOSize:\u00a0" + node.getUnclaimedFIFOSize());
- overviewList.addChild("li", "RAMBucketPoolSize:\u00a0" + SizeUtil.formatSize(core.tempBucketFactory.getRamUsed())+ " / "+ SizeUtil.formatSize(core.tempBucketFactory.getMaxRamUsed()));
- overviewList.addChild("li", "uptimeAverage:\u00a0" + fix3p1pct.format(node.uptime.getUptime()));
+ overviewList.addChild("li", "RAMBucketPoolSize:\u00a0" + SizeUtil.formatSize(core.getTempBucketFactory().getRamUsed())+ " / "+ SizeUtil.formatSize(core.getTempBucketFactory().getMaxRamUsed()));
+ overviewList.addChild("li", "uptimeAverage:\u00a0" + fix3p1pct.format(node.getUptimeEstimator().getUptime()));
long[] decoded = IncomingPacketFilterImpl.getDecodedPackets();
if(decoded != null) {
@@ -1394,15 +1397,15 @@ private void addNodeCircle (HTMLNode circleTable, double myLocation) {
for(int i=0; i MAX_CIRCLE_AGE_THRESHOLD ) {
age = MAX_CIRCLE_AGE_THRESHOLD;
}
strength = 1 - ((double) age / MAX_CIRCLE_AGE_THRESHOLD );
- histogramIndex = (int) (Math.floor(location.doubleValue() * HISTOGRAM_LENGTH));
+ histogramIndex = (int) (Math.floor(location * HISTOGRAM_LENGTH));
histogram[histogramIndex]++;
- nodeCircleInfoboxContent.addChild("span", new String[] { "style", "class" }, new String[] { generatePeerCircleStyleString(location.doubleValue(), false, strength), "connected" }, "x");
+ nodeCircleInfoboxContent.addChild("span", new String[] { "style", "class" }, new String[] { generatePeerCircleStyleString(location, false, strength), "connected" }, "x");
}
nodeCircleInfoboxContent.addChild("span", new String[] { "style", "class" }, new String[] { generatePeerCircleStyleString(myLocation, true, 1.0), "me" }, "x");
//
diff --git a/src/freenet/clients/http/SymlinkerToadlet.java b/src/freenet/clients/http/SymlinkerToadlet.java
index ebcb6b237ba..2a5c129772a 100644
--- a/src/freenet/clients/http/SymlinkerToadlet.java
+++ b/src/freenet/clients/http/SymlinkerToadlet.java
@@ -28,7 +28,7 @@ public class SymlinkerToadlet extends Toadlet {
public SymlinkerToadlet(HighLevelSimpleClient client,final Node node) {
super(client);
this.node = node;
- tslconfig = node.config.createSubConfig("toadletsymlinker");
+ tslconfig = node.getConfig().createSubConfig("toadletsymlinker");
tslconfig.register("symlinks", null, 9, true, false, "SymlinkerToadlet.symlinks", "SymlinkerToadlet.symlinksLong",
new StringArrCallback() {
@Override
@@ -73,7 +73,7 @@ public boolean addLink(String alias, String target, boolean store) {
}
Logger.normal(this, "Adding link: " + alias + " => " + target);
}
- if(store) node.clientCore.storeConfig();
+ if(store) node.getClientCore().storeConfig();
return ret;
}
@@ -88,7 +88,7 @@ public boolean removeLink(String alias, boolean store) {
Logger.normal(this, "Removing link: " + alias + " => " + o);
}
- if(store) node.clientCore.storeConfig();
+ if(store) node.getClientCore().storeConfig();
return ret;
}
diff --git a/src/freenet/clients/http/Toadlet.java b/src/freenet/clients/http/Toadlet.java
index 9f4c1171f50..def85639747 100644
--- a/src/freenet/clients/http/Toadlet.java
+++ b/src/freenet/clients/http/Toadlet.java
@@ -6,9 +6,9 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URI;
+import java.nio.charset.StandardCharsets;
import freenet.client.FetchContext;
import freenet.client.FetchException;
@@ -314,7 +314,7 @@ protected void writeReply(ToadletContext context, int code, String mimeType, Str
}
protected void writeReply(ToadletContext context, int code, String mimeType, String desc, MultiValueTable headers, String reply, boolean forceDisableJavascript) throws ToadletContextClosedException, IOException {
- byte[] buffer = reply.getBytes("UTF-8");
+ byte[] buffer = reply.getBytes(StandardCharsets.UTF_8);
writeReply(context, code, mimeType, desc, headers, buffer, 0, buffer.length, forceDisableJavascript);
}
@@ -357,12 +357,7 @@ static void writePermanentRedirect(ToadletContext ctx, String msg, String locati
""+msg+"" +
l10n("permRedirectWithReason", "reason", msg)+
"
"+l10n("clickHere")+"";
- byte[] buf;
- try {
- buf = redirDoc.getBytes("UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new Error("Impossible: JVM doesn't support UTF-8: " + e, e);
- }
+ byte[] buf = redirDoc.getBytes(StandardCharsets.UTF_8);
ctx.sendReplyHeaders(301, "Moved Permanently", mvt, "text/html; charset=UTF-8", buf.length);
ctx.writeData(buf, 0, buf.length);
}
@@ -389,12 +384,7 @@ protected void writeTemporaryRedirect(ToadletContext ctx, String msg, String loc
l10n("tempRedirectWithReason", "reason", msg)+
"" +
l10n("clickHere") + "