Giter VIP home page Giter VIP logo

webdav-nio-adapter's Introduction

Build Status Codacy Badge Codacy Badge Maven Central Javadocs

webdav-nio-adapter

Serves directory contents specified by a java.nio.file.Path via a WebDAV servlet.

Uses Jackrabbit and an embedded Jetty to server the servlet.

Maven integration

<dependencies>
  <dependency>
    <groupId>org.cryptomator</groupId>
    <artifactId>webdav-nio-adapter</artifactId>
    <version>1.0.0</version>
  </dependency>
</dependencies>

License

This project is dual-licensed under the AGPLv3 for FOSS projects as well as a commercial license for independent software vendors and resellers. If you want to use this library in applications, that are not licensed under the AGPL, feel free to contact our support team.

webdav-nio-adapter's People

Contributors

dependabot[bot] avatar infeo avatar janirutec avatar markuskreusch avatar overheadhunter avatar purejava avatar snyk-bot avatar tobihagemann avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

webdav-nio-adapter's Issues

Autodetect GVFS preferred URL scheme

Currently one has to manually decide to use either dav: or webdav:. It would be way more comfortable, if the application could somehow detect what scheme is supported by the OS.

Allow PROPFIND on /

From @overheadhunter on April 15, 2016 15:59

Linux Mint's WebDAV client makes a PROPFIND request to / during mount.

2016-04-15 17:53:51,300 DEBUG [Server:506] REQUEST on HttpChannelOverHttp@4fb693e{r=4,c=false,a=DISPATCHED,uri=/}
OPTIONS //localhost:37206/
Host: localhost:37206
Accept-Encoding: gzip, deflate
Accept-Language: de-de, de;q=0.9
Connection: keep-alive
User-Agent: gvfs/1.20.3


2016-04-15 17:53:51,300 DEBUG [Server:520] RESPONSE for / h=true
204 null
Date: Fri, 15 Apr 2016 15:53:51 GMT
DAV: 1, 2
MS-Author-Via: DAV


2016-04-15 17:53:51,343 DEBUG [Server:506] REQUEST on HttpChannelOverHttp@2019fe26{r=1,c=false,a=DISPATCHED,uri=/}
PROPFIND //localhost:37206/
Host: localhost:37206
Depth: 0
Content-Type: application/xml
Accept-Encoding: gzip, deflate
Accept-Language: de-de, de;q=0.9
Connection: keep-alive
Content-Length: 124
User-Agent: gvfs/1.20.3


2016-04-15 17:53:51,354 DEBUG [Server:520] RESPONSE for / h=true
501 Method PROPFIND is not defined in RFC 2068 and is not supported by the Servlet API 
Date: Fri, 15 Apr 2016 15:53:51 GMT
Cache-Control: must-revalidate,no-cache,no-store
Content-Type: text/html;charset=iso-8859-1
Content-Length: 390

Copied from original issue: cryptomator/cryptomator#235

Error mounting with WindowsMounter: System error 67 has occurred.

Running the mirror test on a fresh, rebooted Windows system, the following error is thrown:

[main] INFO org.cryptomator.frontend.webdav.WebDavServer - Binding server socket to localhost:8080
[main] INFO org.eclipse.jetty.server.AbstractConnector - Started ServerConnector@4cc0edeb{HTTP/1.1, (http/1.1)}{localhost:8080}
[main] INFO org.eclipse.jetty.server.Server - jetty-10.0.12; built: 2022-09-14T01:54:40.076Z; git: 408d0139887e27a57b54ed52e2d92a36731a7e88; jvm 19.0.1+10
[main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.s.ServletContextHandler@380fb434{/,null,AVAILABLE}
[main] INFO org.eclipse.jetty.server.Server - Started Server@13eb8acf{STARTING}[10.0.12,sto=0] @3781ms
[main] INFO org.cryptomator.frontend.webdav.WebDavServer - WebDavServer started.
[main] INFO org.eclipse.jetty.server.session.DefaultSessionIdManager - Session workerName=node0
[main] INFO org.apache.jackrabbit.webdav.server.AbstractWebdavServlet - authenticate-header = Basic realm="Jackrabbit Webdav Server"
[main] INFO org.apache.jackrabbit.webdav.server.AbstractWebdavServlet - csrf-protection = null
[main] INFO org.apache.jackrabbit.webdav.server.AbstractWebdavServlet - createAbsoluteURI = true
[main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.s.ServletContextHandler@501edcf1{/test,null,AVAILABLE}
[main] INFO org.cryptomator.frontend.webdav.servlet.WebDavServletController - WebDavServlet started: /test
[main] INFO org.cryptomator.frontend.webdav.servlet.WebDavServletController - Mounting http://localhost:8080/test using org.cryptomator.frontend.webdav.mount.WindowsMounter
Exception in thread "main" org.cryptomator.frontend.webdav.mount.Mounter$CommandFailedException: Command failed with exit code 2. Expected 0. Stderr: System error 67 has occurred.

The network name cannot be found.


	at org.cryptomator.frontend.webdav.mount.ProcessUtil.assertExitValue(ProcessUtil.java:28)
	at org.cryptomator.frontend.webdav.mount.WindowsMounter.mount(WindowsMounter.java:43)
	at org.cryptomator.frontend.webdav.servlet.WebDavServletController.mount(WebDavServletController.java:96)
	at org.cryptomator.frontend.webdav.MirroringTest.main(MirroringTest.java:40)

Process finished with exit code 130

ERROR [Vault:144] Unable to mount filesystem

I have encountered the following problem with the release candidate Cryptomator 1.3.0-rc3 on Linux 4.8.0-49-generic (amd64) under Ubuntu 16.04 (64 Bit) with using the webdav schema option instead of dav.

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 16.04.2 LTS
Release:	16.04
Codename:	xenial
$ java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

The Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy is installed/enabled.

The problem seems to be reproducible on my machine also with a new session.

$ cat ~/.Cryptomator/cryptomator.log
2017-04-27 12:13:53,970 INFO  [Cryptomator:21] Starting Cryptomator 1.3.0-rc3 on Linux 4.8.0-49-generic (amd64)
2017-04-27 12:13:54,228 INFO  [MainApplication:19] JavaFX application started.
2017-04-27 12:13:54,315 INFO  [SettingsProvider:100] Settings loaded from /home/sebastian/.Cryptomator/settings.json
2017-04-27 12:13:54,317 DEBUG [DebugMode:46] Debug mode initialized
2017-04-27 12:13:54,320 DEBUG [Localization:45] Loaded localization default file: /localization/en.txt
2017-04-27 12:13:54,320 INFO  [Localization:49] Detected language "de" and region "DE"
2017-04-27 12:13:54,320 INFO  [Localization:54] Attempting to load localization from: /localization/de_DE.txt
2017-04-27 12:13:54,321 INFO  [Localization:59] Attempting to load localization from: /localization/de.txt
2017-04-27 12:13:54,812 DEBUG [WelcomeController:127] Checking for updates...
2017-04-27 12:13:55,186 INFO  [log:192] Logging initialized @1735ms to org.eclipse.jetty.util.log.Slf4jLog
2017-04-27 12:13:55,267 INFO  [WebDavServer:70] Binding server socket to localhost:42427
2017-04-27 12:13:55,278 INFO  [AbstractConnector:280] Started ServerConnector@6afe53e2{HTTP/1.1,[http/1.1]}{localhost:42427}
2017-04-27 12:13:55,328 INFO  [SettingsProvider:129] Settings saved to /home/sebastian/.Cryptomator/settings.json
2017-04-27 12:13:56,063 INFO  [WelcomeController:163] Current version: 1.3.0-rc3, lastest version: 1.2.3
2017-04-27 12:14:22,135 INFO  [Server:372] jetty-9.4.4.v20170414
2017-04-27 12:14:22,180 INFO  [ContextHandler:788] Started o.e.j.s.ServletContextHandler@4f3fb79b{/,null,AVAILABLE}
2017-04-27 12:14:22,182 INFO  [Server:444] Started @28732ms
2017-04-27 12:14:22,182 INFO  [WebDavServer:94] WebDavServer started.
2017-04-27 12:14:22,252 INFO  [session:364] DefaultSessionIdManager workerName=node0
2017-04-27 12:14:22,253 INFO  [session:369] No SessionScavenger set, using defaults
2017-04-27 12:14:22,254 INFO  [session:149] Scavenging every 660000ms
2017-04-27 12:14:22,262 INFO  [AbstractWebdavServlet:170] authenticate-header = Basic realm="Jackrabbit Webdav Server"
2017-04-27 12:14:22,264 INFO  [AbstractWebdavServlet:175] csrf-protection = null
2017-04-27 12:14:22,264 INFO  [AbstractWebdavServlet:182] createAbsoluteURI = true
2017-04-27 12:14:22,264 INFO  [ContextHandler:788] Started o.e.j.s.ServletContextHandler@442b1a88{/teGOsrDbSc59/vault,null,AVAILABLE}
2017-04-27 12:14:22,265 INFO  [WebDavServletController:51] WebDavServlet started: /teGOsrDbSc59/vault
2017-04-27 12:14:22,267 INFO  [WebDavServletController:94] Mounting http://localhost:42427/teGOsrDbSc59/vault using org.cryptomator.frontend.webdav.mount.LinuxGvfsMounter
2017-04-27 12:14:22,295 ERROR [Vault:144] Unable to mount filesystem
org.cryptomator.frontend.webdav.mount.Mounter$CommandFailedException: Command failed with exit code 2. Expected 0. Stderr: Fehler beim Einhängen des Ortes: Ort kann nicht eingehängt werden

	at org.cryptomator.frontend.webdav.mount.ProcessUtil.assertExitValue(ProcessUtil.java:28) ~[webdav-nio-adapter-0.5.1.jar:?]
	at org.cryptomator.frontend.webdav.mount.LinuxGvfsMounter.mount(LinuxGvfsMounter.java:44) ~[webdav-nio-adapter-0.5.1.jar:?]
	at org.cryptomator.frontend.webdav.servlet.WebDavServletController.mount(WebDavServletController.java:95) ~[webdav-nio-adapter-0.5.1.jar:?]
	at org.cryptomator.ui.model.Vault.mount(Vault.java:139) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.controllers.UnlockController.unlock(UnlockController.java:342) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.controllers.UnlockController.lambda$didClickUnlockButton$0(UnlockController.java:335) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.util.AsyncTaskService.lambda$asyncTaskOf$0(AsyncTaskService.java:37) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.util.AsyncTaskService$AsyncTaskImpl.lambda$null$6(AsyncTaskService.java:94) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.util.AsyncTaskService.logExceptions(AsyncTaskService.java:123) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.util.AsyncTaskService.access$100(AsyncTaskService.java:24) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.util.AsyncTaskService$AsyncTaskImpl.lambda$run$7(AsyncTaskService.java:92) ~[ui-1.3.0-rc3.jar:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_112]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_112]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_112]
2017-04-27 12:14:48,440 INFO  [ContextHandler:957] Stopped o.e.j.s.ServletContextHandler@442b1a88{/teGOsrDbSc59/vault,null,UNAVAILABLE}
2017-04-27 12:14:48,440 INFO  [WebDavServletController:65] WebDavServlet stopped: /teGOsrDbSc59/vault
2017-04-27 12:15:01,770 INFO  [MainApplication:40] JavaFX application stopped.
2017-04-27 12:15:01,787 DEBUG [InterProcessCommunicator:158] Server shut down.
2017-04-27 12:15:01,791 DEBUG [CleanShutdownPerformer:16] Running graceful shutdown tasks...
$ cat ~/.Cryptomator/cryptomator.log
2017-04-27 12:35:28,978 INFO  [Cryptomator:21] Starting Cryptomator 1.3.0-rc3 on Linux 4.8.0-49-generic (amd64)
2017-04-27 12:35:29,376 INFO  [MainApplication:19] JavaFX application started.
2017-04-27 12:35:29,450 INFO  [SettingsProvider:100] Settings loaded from /home/sebastian/.Cryptomator/settings.json
2017-04-27 12:35:29,451 DEBUG [DebugMode:46] Debug mode initialized
2017-04-27 12:35:29,454 DEBUG [Localization:45] Loaded localization default file: /localization/en.txt
2017-04-27 12:35:29,454 INFO  [Localization:49] Detected language "de" and region "DE"
2017-04-27 12:35:29,454 INFO  [Localization:54] Attempting to load localization from: /localization/de_DE.txt
2017-04-27 12:35:29,455 INFO  [Localization:59] Attempting to load localization from: /localization/de.txt
2017-04-27 12:35:29,949 DEBUG [WelcomeController:127] Checking for updates...
2017-04-27 12:35:30,360 INFO  [log:192] Logging initialized @1877ms to org.eclipse.jetty.util.log.Slf4jLog
2017-04-27 12:35:30,413 INFO  [WebDavServer:70] Binding server socket to localhost:42427
2017-04-27 12:35:30,423 INFO  [AbstractConnector:280] Started ServerConnector@62eb71a5{HTTP/1.1,[http/1.1]}{localhost:42427}
2017-04-27 12:35:30,433 INFO  [WelcomeController:163] Current version: 1.3.0-rc3, lastest version: 1.2.3
2017-04-27 12:35:30,458 INFO  [SettingsProvider:129] Settings saved to /home/sebastian/.Cryptomator/settings.json
2017-04-27 12:35:39,962 INFO  [Server:372] jetty-9.4.4.v20170414
2017-04-27 12:35:40,007 INFO  [ContextHandler:788] Started o.e.j.s.ServletContextHandler@6355c522{/,null,AVAILABLE}
2017-04-27 12:35:40,008 INFO  [Server:444] Started @11526ms
2017-04-27 12:35:40,008 INFO  [WebDavServer:94] WebDavServer started.
2017-04-27 12:35:40,103 INFO  [session:364] DefaultSessionIdManager workerName=node0
2017-04-27 12:35:40,103 INFO  [session:369] No SessionScavenger set, using defaults
2017-04-27 12:35:40,106 INFO  [session:149] Scavenging every 660000ms
2017-04-27 12:35:40,114 INFO  [AbstractWebdavServlet:170] authenticate-header = Basic realm="Jackrabbit Webdav Server"
2017-04-27 12:35:40,116 INFO  [AbstractWebdavServlet:175] csrf-protection = null
2017-04-27 12:35:40,117 INFO  [AbstractWebdavServlet:182] createAbsoluteURI = true
2017-04-27 12:35:40,117 INFO  [ContextHandler:788] Started o.e.j.s.ServletContextHandler@4a4970f8{/teGOsrDbSc59/vault,null,AVAILABLE}
2017-04-27 12:35:40,118 INFO  [WebDavServletController:51] WebDavServlet started: /teGOsrDbSc59/vault
2017-04-27 12:35:40,120 INFO  [WebDavServletController:94] Mounting http://localhost:42427/teGOsrDbSc59/vault using org.cryptomator.frontend.webdav.mount.LinuxGvfsMounter
2017-04-27 12:35:40,158 ERROR [Vault:144] Unable to mount filesystem
org.cryptomator.frontend.webdav.mount.Mounter$CommandFailedException: Command failed with exit code 2. Expected 0. Stderr: Fehler beim Einhängen des Ortes: Ort kann nicht eingehängt werden

	at org.cryptomator.frontend.webdav.mount.ProcessUtil.assertExitValue(ProcessUtil.java:28) ~[webdav-nio-adapter-0.5.1.jar:?]
	at org.cryptomator.frontend.webdav.mount.LinuxGvfsMounter.mount(LinuxGvfsMounter.java:44) ~[webdav-nio-adapter-0.5.1.jar:?]
	at org.cryptomator.frontend.webdav.servlet.WebDavServletController.mount(WebDavServletController.java:95) ~[webdav-nio-adapter-0.5.1.jar:?]
	at org.cryptomator.ui.model.Vault.mount(Vault.java:139) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.controllers.UnlockController.unlock(UnlockController.java:342) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.controllers.UnlockController.lambda$didClickUnlockButton$0(UnlockController.java:335) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.util.AsyncTaskService.lambda$asyncTaskOf$0(AsyncTaskService.java:37) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.util.AsyncTaskService$AsyncTaskImpl.lambda$null$6(AsyncTaskService.java:94) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.util.AsyncTaskService.logExceptions(AsyncTaskService.java:123) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.util.AsyncTaskService.access$100(AsyncTaskService.java:24) ~[ui-1.3.0-rc3.jar:?]
	at org.cryptomator.ui.util.AsyncTaskService$AsyncTaskImpl.lambda$run$7(AsyncTaskService.java:92) ~[ui-1.3.0-rc3.jar:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_112]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_112]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_112]
2017-04-27 12:36:38,109 INFO  [ContextHandler:957] Stopped o.e.j.s.ServletContextHandler@4a4970f8{/teGOsrDbSc59/vault,null,UNAVAILABLE}
2017-04-27 12:36:38,110 INFO  [WebDavServletController:65] WebDavServlet stopped: /teGOsrDbSc59/vault
2017-04-27 12:36:39,849 INFO  [MainApplication:40] JavaFX application stopped.
2017-04-27 12:36:39,859 DEBUG [InterProcessCommunicator:158] Server shut down.

Files containing "%" cannot be opened

Files containing a % cannot be opened anymore. Activating the debug log level, the following stack trace appears in the log when accessing the file:

org.eclipse.jetty.http.BadMessageException: 400: Ambiguous path encoding in URI
	at org.eclipse.jetty.server.Request.setMetaData(Request.java:1706)
	at org.eclipse.jetty.server.HttpChannel.onRequest(HttpChannel.java:794)
	at org.eclipse.jetty.server.HttpChannelOverHttp.headerComplete(HttpChannelOverHttp.java:332)
	at org.eclipse.jetty.http.HttpParser.parseFields(HttpParser.java:1226)
	at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1511)
	at org.eclipse.jetty.server.HttpConnection.parseRequestBuffer(HttpConnection.java:384)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:270)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:319)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
	at org.eclipse.jetty.io.SocketChannelEndPoint$1.run(SocketChannelEndPoint.java:101)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:378)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
	at java.base/java.lang.Thread.run(Thread.java:831)

This bug first appeared when updating jetty from 10.0.2 to 10.0.3 in 99594ed.

Mounting on linux systems with KDE

Description

Even if gio or gvfs is installed on the regarding system, if one uses KDE as the desktop environment a filesystem cannot be mounted. By calling mount(), the following stacktrace is shown:

Caused by: org.cryptomator.frontend.webdav.mount.Mounter$CommandFailedException: Command failed with exit code 2. Expected 0. Stderr: gio: webdav://localhost:42427/qbZJ29z6d546/asd: volume doesn’t implement mount

	at org.cryptomator.frontend.webdav.mount.ProcessUtil.assertExitValue(ProcessUtil.java:28)
	at org.cryptomator.frontend.webdav.mount.LinuxGioMounter.mount(LinuxGioMounter.java:39)
	at org.cryptomator.frontend.webdav.servlet.WebDavServletController.mount(WebDavServletController.java:102)
	at org.cryptomator.common.vaults.WebDavVolume.mount(WebDavVolume.java:62)
	... 12 more

The adapter uses the gio tool to mount the (local) network location, but for KDE it relied on the quite old and unmainted KIO-GIO package, which seems to lost functionality in newer KDE versions.

The problem of mounting network locations with KDE persisted for a long time, see https://bugs.kde.org/show_bug.cgi?id=75324. Since beginning of this year there exists a new approach with KIO-FUSE, but it is not included in the standard packages sources yet (and does not look 100% stable).

Remark

This is the upstream issue for cryptomator/cryptomator#1381

Add TLS support

Add an option to load a key-pair from a given path and encrypt connections using TLS via Jetty.

Error when mounting with LinuxGioMounter: `Message is already in session queue`

LinuxGioMounter fails to mount in some cases:

java.io.IOException: Command failed with exit code 2. Expected 0.
	at [email protected]/org.cryptomator.frontend.webdav.mount.ProcessUtil.assertExitValue(ProcessUtil.java:25)
	at [email protected]/org.cryptomator.frontend.webdav.mount.LinuxGioMounter$MountBuilderImpl.mount(LinuxGioMounter.java:97)
	... 13 more
Caused by: java.io.IOException: Stderr output: gio: dav://localhost:42427/lsLoxEBKL0GZ: Message is already in session queue
	at [email protected]/org.cryptomator.frontend.webdav.mount.ProcessUtil.assertExitValue(ProcessUtil.java:23)

@infeo found this possibly related upstream bug in gvfs: https://gitlab.gnome.org/GNOME/gvfs/-/issues/630. Looks like a trailing slash in the URL may make the difference. However I am not sure, this really changed:

With webdav-nio-adapter version 1.2.8 (Cryptomator 1.6.17) this was the implementation:

URI schemeCorrectedUri = new URI(mountParams.getOrDefault(MountParam.PREFERRED_GVFS_SCHEME, DEFAULT_GIO_SCHEME), uri.getSchemeSpecificPart(), null);
ProcessBuilder mountCmd = new ProcessBuilder("sh", "-c", "gio mount \"" + schemeCorrectedUri.toASCIIString() + "\"");

With webdav-nio-adapter version 2.0.0 (Cryptomator 1.7.0) it doesn't look any different:

URI schemeCorrectedUri = new URI(WEBDAV_URI_SCHEME, uri.getSchemeSpecificPart(), null);
// mount:
ProcessBuilder mountCmd = new ProcessBuilder("sh", "-c", "gio mount \"" + schemeCorrectedUri.toASCIIString() + "\"");

fusedav can write files to cryptomator on Ubuntu Linux 17.10, but gets back nulls when reading them

I have Ubuntu Linux 17.10 x86_64, cryptomator 1.3.2-0ppa2 from the cryptomator repository, and fusedav 0.2-3.1 from the Ubuntu repository.

When I unlock my vault in the cryptomator GUI and then try to mount it with fusedav, fusedav spits out several complaints about PROPFIND failures, but then seems to mount the filesystem anyway. I see that these PROPFIND errors are commented on in other issues within this project and are apparently save to ignore, but there's another issue...

Once I've mounted my cryptomator WebDAV URL with fusedav, I am able to write files into the fuse filesystem with no trouble. E.g., if I've mounted on ~/c, then echo foo > ~/c/bar.txt works just fine, and if I then double-click on bar.txt in the cryptomator GUI, it indeed has the contents I expect, i.e., the word "foo" followed by a newline.

However, if I type cat ~/c/bar.txt at the command line, I get back nothing. Well, actually, not nothing. It's getting back nulls where the characters of the file should be:

$ cat ~/c/bar.txt | od -x
0000000 0000 0000
0000004
$ 

Is this a known issue? Is there a fix?

Thanks.

Can not reuse server instance

A server instance can not be restarted because its threadpool gets terminated:

server = WebDavServer.create();
server.start();
server.stop(); // will terminate internal threadpool
server.start(); // can no longer submit new tasks to threadpool

Error mounting with WindowsMounter and fixed Driveletter: Systemerror 67

Using the WindowsMounter and specifiying a drive letter as an absolute path (i.e., C:\), the mirror examples fails with:

13:20:13.122 [main] INFO org.cryptomator.frontend.webdav.MirroringTest - Using mount provider: WebDAV (Windows Explorer)
13:20:13.126 [main] INFO org.cryptomator.frontend.webdav.MirroringTest - Enter path to the directory you want to be accessible via WebDAV:
T:\test
13:20:16.206 [main] INFO org.eclipse.jetty.server.Server - jetty-10.0.14; built: 2023-02-22T23:12:32.272Z; git: 976721d0f3e903a243584d47870ad2f2c1bf9e55; jvm 17.0.2+8
13:20:16.247 [main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.s.ServletContextHandler@57baeedf{/,null,AVAILABLE}
13:20:16.331 [main] INFO org.eclipse.jetty.server.AbstractConnector - Started ServerConnector@23e028a9{HTTP/1.1, (http/1.1)}{localhost:8080}
13:20:16.339 [main] INFO org.eclipse.jetty.server.Server - Started Server@15d0c81b{STARTING}[10.0.14,sto=0] @3511ms
13:20:16.339 [main] INFO org.cryptomator.frontend.webdav.WebDavServer - WebDavServer started.
13:20:16.366 [main] INFO org.eclipse.jetty.server.session.DefaultSessionIdManager - Session workerName=node0
13:20:16.376 [main] INFO org.apache.jackrabbit.webdav.server.AbstractWebdavServlet - authenticate-header = Basic realm="Jackrabbit Webdav Server"
13:20:16.377 [main] INFO org.apache.jackrabbit.webdav.server.AbstractWebdavServlet - csrf-protection = null
13:20:16.377 [main] INFO org.apache.jackrabbit.webdav.server.AbstractWebdavServlet - createAbsoluteURI = true
13:20:16.377 [main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.s.ServletContextHandler@71b1176b{/testMount/testName,null,AVAILABLE}
13:20:16.377 [main] INFO org.cryptomator.frontend.webdav.servlet.WebDavServletController - WebDavServlet started: /testMount/testName
13:20:16.377 [main] INFO org.cryptomator.frontend.webdav.mount.AbstractMountBuilder - Mounting http://localhost:8080/testMount/testName...
13:20:16.397 [main] DEBUG org.cryptomator.frontend.webdav.mount.WindowsMounter - Original Registry value for ProxyOverride is: localhost;<local>;localhost:8080;cryptomator-vault:42427;cryptomator-vault
13:20:16.398 [main] DEBUG org.cryptomator.frontend.webdav.mount.WindowsMounter - Setting Registry value for ProxyOverride to: localhost;<local>;localhost:8080;cryptomator-vault:42427;cryptomator-vault
13:20:16.453 [main] INFO org.eclipse.jetty.server.Server - Stopped Server@15d0c81b{STOPPING}[10.0.14,sto=0]
13:20:16.456 [main] INFO org.eclipse.jetty.server.AbstractConnector - Stopped ServerConnector@23e028a9{HTTP/1.1, (http/1.1)}{localhost:8080}
13:20:16.458 [main] INFO org.eclipse.jetty.server.handler.ContextHandler - Stopped o.e.j.s.ServletContextHandler@57baeedf{/,null,STOPPED}
13:20:16.459 [main] INFO org.cryptomator.frontend.webdav.WebDavServer - WebDavServer stopped.
Exception in thread "main" org.cryptomator.integrations.mount.MountFailedException: java.io.IOException: Command failed with exit code 2. Expected 0.
	at org.cryptomator.frontend.webdav.mount.WindowsMounter$MountBuilderImpl.mount(WindowsMounter.java:130)
	at org.cryptomator.frontend.webdav.mount.AbstractMountBuilder.mount(AbstractMountBuilder.java:88)
	at org.cryptomator.frontend.webdav.MirroringTest.main(MirroringTest.java:58)
Caused by: java.io.IOException: Command failed with exit code 2. Expected 0.
	at org.cryptomator.frontend.webdav.mount.ProcessUtil.assertExitValue(ProcessUtil.java:25)
	at org.cryptomator.frontend.webdav.mount.WindowsMounter$MountBuilderImpl.mount(WindowsMounter.java:117)
	... 2 more
Caused by: java.io.IOException: Stderr output: System error 67 has occurred.

The network name cannot be found.

	at org.cryptomator.frontend.webdav.mount.ProcessUtil.assertExitValue(ProcessUtil.java:23)
	... 3 more

Process finished with exit code 1

If the drive letter is specified as a relative path (i.e., C:), it works

Ignore empty directory file

Related to cryptomator/cryptofs#8.

Expected

Contents of a directory should be shown even if there is an empty directory file. So it should be just ignored.

Actual

Contents of a directory aren't shown if there is an empty directory file inside.

Stack Trace

2017-04-20 16:36:17,254 WARN  [HttpChannel:507] /<redacted>/Vault/
java.io.UncheckedIOException: java.io.IOException: Failed to load contents of directory file at path /<redacted>/Vault/d/OS/MBBIKIS7IOQHA2CCEVEUOIVZ4NORXW/0R26YAMEPAX27VPMMK2C3TORNOJQJM3MEVYGYS2KPMRWOUNBM
	at org.cryptomator.frontend.webdav.servlet.DavFolder.getMembers(DavFolder.java:114) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.apache.jackrabbit.webdav.MultiStatus.addResourceProperties(MultiStatus.java:63) ~[jackrabbit-webdav-2.15.0.jar:?]
	at org.apache.jackrabbit.webdav.server.AbstractWebdavServlet.doPropFind(AbstractWebdavServlet.java:561) ~[jackrabbit-webdav-2.15.0.jar:?]
	at org.apache.jackrabbit.webdav.server.AbstractWebdavServlet.execute(AbstractWebdavServlet.java:349) ~[jackrabbit-webdav-2.15.0.jar:?]
	at org.cryptomator.frontend.webdav.servlet.WebDavServlet.execute(WebDavServlet.java:106) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.apache.jackrabbit.webdav.server.AbstractWebdavServlet.service(AbstractWebdavServlet.java:292) ~[jackrabbit-webdav-2.15.0.jar:?]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) ~[javax.servlet-api-3.1.0.jar:3.1.0]
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:841) ~[jetty-servlet-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1634) ~[jetty-servlet-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.cryptomator.frontend.webdav.servlet.MacChunkedPutCompatibilityFilter.doFilterHttp(MacChunkedPutCompatibilityFilter.java:58) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.cryptomator.frontend.webdav.servlet.HttpFilter.doFilter(HttpFilter.java:26) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1621) ~[jetty-servlet-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.cryptomator.frontend.webdav.servlet.AcceptRangeFilter.doFilterHttp(AcceptRangeFilter.java:38) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.cryptomator.frontend.webdav.servlet.HttpFilter.doFilter(HttpFilter.java:26) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1621) ~[jetty-servlet-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.cryptomator.frontend.webdav.servlet.MkcolComplianceFilter.doFilterHttp(MkcolComplianceFilter.java:42) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.cryptomator.frontend.webdav.servlet.HttpFilter.doFilter(HttpFilter.java:26) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1621) ~[jetty-servlet-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.cryptomator.frontend.webdav.servlet.PostRequestBlockingFilter.doFilterHttp(PostRequestBlockingFilter.java:41) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.cryptomator.frontend.webdav.servlet.HttpFilter.doFilter(HttpFilter.java:26) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1621) ~[jetty-servlet-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.cryptomator.frontend.webdav.servlet.UnicodeResourcePathNormalizationFilter.doFilterHttp(UnicodeResourcePathNormalizationFilter.java:68) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.cryptomator.frontend.webdav.servlet.HttpFilter.doFilter(HttpFilter.java:26) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1621) ~[jetty-servlet-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.cryptomator.frontend.webdav.servlet.LoggingFilter.doFilterHttp(LoggingFilter.java:44) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.cryptomator.frontend.webdav.servlet.HttpFilter.doFilter(HttpFilter.java:26) ~[webdav-nio-adapter-0.4.0.jar:?]
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1621) ~[jetty-servlet-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:541) ~[jetty-servlet-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1592) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1239) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:481) ~[jetty-servlet-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1561) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1141) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:213) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.Server.handle(Server.java:564) ~[jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:320) [jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251) [jetty-server-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279) [jetty-io-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110) [jetty-io-9.4.2.v20170220.jar:9.4.2.v20170220]
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124) [jetty-io-9.4.2.v20170220.jar:9.4.2.v20170220]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_131]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_131]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]
Caused by: java.io.IOException: Failed to load contents of directory file at path /<redacted>/Vault/d/OS/MBBIKIS7IOQHA2CCEVEUOIVZ4NORXW/0R26YAMEPAX27VPMMK2C3TORNOJQJM3MEVYGYS2KPMRWOUNBM
	at org.cryptomator.cryptofs.DirectoryIdProvider.load(DirectoryIdProvider.java:36) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoPathMapper.getCiphertextDir(CryptoPathMapper.java:88) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoPathMapper.getCiphertextDirPath(CryptoPathMapper.java:75) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoFileSystemImpl.readAttributes(CryptoFileSystemImpl.java:233) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoFileSystemProvider.readAttributes(CryptoFileSystemProvider.java:257) ~[cryptofs-1.2.0.jar:?]
	at java.nio.file.Files.readAttributes(Files.java:1737) ~[?:1.8.0_131]
	at org.cryptomator.frontend.webdav.servlet.DavFolder.getMembers(DavFolder.java:102) ~[webdav-nio-adapter-0.4.0.jar:?]
	... 48 more
Caused by: java.util.concurrent.ExecutionException: java.io.IOException: Invalid, empty directory file: /<redacted>/Vault/d/OS/MBBIKIS7IOQHA2CCEVEUOIVZ4NORXW/0R26YAMEPAX27VPMMK2C3TORNOJQJM3MEVYGYS2KPMRWOUNBM
	at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:502) ~[guava-21.0.jar:?]
	at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:461) ~[guava-21.0.jar:?]
	at com.google.common.util.concurrent.AbstractFuture$TrustedFuture.get(AbstractFuture.java:78) ~[guava-21.0.jar:?]
	at com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly(Uninterruptibles.java:142) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache$Segment.getAndRecordStats(LocalCache.java:2461) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2425) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2298) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2211) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache.get(LocalCache.java:4154) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:4158) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:5147) ~[guava-21.0.jar:?]
	at org.cryptomator.cryptofs.DirectoryIdProvider.load(DirectoryIdProvider.java:34) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoPathMapper.getCiphertextDir(CryptoPathMapper.java:88) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoPathMapper.getCiphertextDirPath(CryptoPathMapper.java:75) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoFileSystemImpl.readAttributes(CryptoFileSystemImpl.java:233) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoFileSystemProvider.readAttributes(CryptoFileSystemProvider.java:257) ~[cryptofs-1.2.0.jar:?]
	at java.nio.file.Files.readAttributes(Files.java:1737) ~[?:1.8.0_131]
	at org.cryptomator.frontend.webdav.servlet.DavFolder.getMembers(DavFolder.java:102) ~[webdav-nio-adapter-0.4.0.jar:?]
	... 48 more
Caused by: java.io.IOException: Invalid, empty directory file: /<redacted>/Vault/d/OS/MBBIKIS7IOQHA2CCEVEUOIVZ4NORXW/0R26YAMEPAX27VPMMK2C3TORNOJQJM3MEVYGYS2KPMRWOUNBM
	at org.cryptomator.cryptofs.DirectoryIdLoader.load(DirectoryIdLoader.java:25) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.DirectoryIdLoader.load(DirectoryIdLoader.java:13) ~[cryptofs-1.2.0.jar:?]
	at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3716) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2424) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2298) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2211) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache.get(LocalCache.java:4154) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:4158) ~[guava-21.0.jar:?]
	at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:5147) ~[guava-21.0.jar:?]
	at org.cryptomator.cryptofs.DirectoryIdProvider.load(DirectoryIdProvider.java:34) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoPathMapper.getCiphertextDir(CryptoPathMapper.java:88) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoPathMapper.getCiphertextDirPath(CryptoPathMapper.java:75) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoFileSystemImpl.readAttributes(CryptoFileSystemImpl.java:233) ~[cryptofs-1.2.0.jar:?]
	at org.cryptomator.cryptofs.CryptoFileSystemProvider.readAttributes(CryptoFileSystemProvider.java:257) ~[cryptofs-1.2.0.jar:?]
	at java.nio.file.Files.readAttributes(Files.java:1737) ~[?:1.8.0_131]
	at org.cryptomator.frontend.webdav.servlet.DavFolder.getMembers(DavFolder.java:102) ~[webdav-nio-adapter-0.4.0.jar:?]
	... 48 more

Update to jetty-server and jetty-servlet 11.0.15

With Spring Boot 3 we have conflicting namespaces with javax and jakarta imports. Is it possible to update to org.eclipse.jetty:jetty-server and org.eclipse.jetty: jetty-servlet to version 11.0.15?

I would like to create a PR if necessary

URI-Normalization causes incomplete RessourcePath

For a general Description, see Issue cryptomator/cryptomator/#556

Steps to Reproduce

  1. Mount some directory with the webdav-nio-adapter
  2. Move the file named "test;)test.txt" over the mounted drive in the folder
  3. open the mounted folder in windows explorer

Expected Results

File should be named "test;)test.txt

Actual Results

File is named "test"

Environment

Version: 1.1.0
OS: Windows 10

Can not rebind socket

Once the server is started, it is no longer possible to bind the server to a different address or port, because the ExecutorService can not be restarted. This is a regression probably caused by updating the jetty dependency.

TO DELETE

Wrong place. This issue can be removed.

Reusing MountParamsBuilder leads to faulty MountParams Instance

For a general Description, see Issue cryptomator/cryptomator/#576

Steps to Reproduce

  1. Create an Instance of MountParams with some random drive letter (for example "X:")
  2. Create another instance of MountParams without a drive letter

Expected Results

The second MountParams object does not have a <key,value> pair for the drive letter

Actual Results

The second MountParams object has a <key,value> pair for the drive letter with value "X:"

Environment

Version: 1.1.0
OS: Windows 10

Dont use jetty classes in servlet

We need to make the servlet server agnostic, ie no longer use any jetty classes.

For example instead of the jetty http header fields we can use com.google.common.net.HttpHeaders

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.