0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Javaペラ1のWebDAVサーバー

0
Posted at

ソース

SimpleWebDavServer.java
import com.sun.net.httpserver.*;
import java.io.*;
import java.net.InetSocketAddress;
import java.nio.file.*;
import java.util.stream.*;

public class SimpleWebDavServer {
    public static void main(String[] args) throws Exception {
        int port = 8080;
        // Ensure rootDir is an absolute path to avoid ambiguity
        String rootDir = Paths.get("./").toAbsolutePath().normalize().toString();
        HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
        server.createContext("/", exchange -> {
            String method = exchange.getRequestMethod();
            // Construct the full path, ensuring it's within the rootDir and normalized
            String requestPath = exchange.getRequestURI().getPath();
            Path path = Paths.get(rootDir, requestPath).normalize();

            // Security check: ensure the resolved path is still within the root directory
            if (!path.startsWith(rootDir)) {
                exchange.sendResponseHeaders(403, -1); // Forbidden
                return;
            }
            try {
                switch (method) {
                    case "GET":
                        if (Files.exists(path)) {
                            if (Files.isDirectory(path)) {
                                // ディレクトリ一覧インデックス表示
                                StringBuilder html = new StringBuilder();
                                html.append("<html><body><h1>Index of ")
                                    .append(exchange.getRequestURI().getPath())
                                    .append("</h1><ul>");
                                try (Stream<Path> stream = Files.list(path)) {
                                    stream.forEach(p -> {
                                        String name = p.getFileName().toString();
                                        html.append("<li><a href=\"")
                                            .append(name)
                                            .append(Files.isDirectory(p) ? "/" : "")
                                            .append("\">")
                                            .append(name)
                                            .append(Files.isDirectory(p) ? "/" : "")
                                            .append("</a></li>");
                                    });
                                }
                                html.append("</ul></body></html>");
                                byte[] bytes = html.toString().getBytes("UTF-8");
                                exchange.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8");
                                exchange.sendResponseHeaders(200, bytes.length);
                                exchange.getResponseBody().write(bytes);
                            } else {
                                exchange.sendResponseHeaders(200, Files.size(path));
                                Files.copy(path, exchange.getResponseBody());
                            }
                        } else {
                            exchange.sendResponseHeaders(404, -1);
                        }
                        break;
                    case "PUT":
                        if (Files.isDirectory(path)) {
                            exchange.sendResponseHeaders(400, -1); // Bad Request: Cannot PUT to a directory
                            break;
                        }
                        try {
                            // Create parent directories if they don't exist
                            Path parentDir = path.getParent();
                            if (parentDir != null && !Files.exists(parentDir)) {
                                Files.createDirectories(parentDir);
                            }

                            // Write the request body to the file
                            try (InputStream is = exchange.getRequestBody();
                                 OutputStream os = Files.newOutputStream(path)) {
                                byte[] buffer = new byte[4096];
                                int len;
                                while ((len = is.read(buffer)) != -1) {
                                    os.write(buffer, 0, len);
                                }
                            }
                            exchange.sendResponseHeaders(201, -1); // Created
                        } catch (FileAlreadyExistsException e) {
                            // This should ideally not happen if Files.newOutputStream overwrites,
                            // but good to catch specific file system errors.
                            System.err.println("Error during PUT request (FileAlreadyExistsException): " + e.getMessage());
                            e.printStackTrace();
                            exchange.sendResponseHeaders(409, -1); // Conflict
                        } catch (AccessDeniedException e) {
                            System.err.println("Error during PUT request (AccessDeniedException): " + e.getMessage());
                            e.printStackTrace();
                            exchange.sendResponseHeaders(403, -1); // Forbidden
                        } catch (IOException e) {
                            System.err.println("Error during PUT request: " + e.getMessage());
                            e.printStackTrace();
                            exchange.sendResponseHeaders(500, -1); // Internal Server Error
                        }
                        break;
                    case "DELETE":
                        Files.deleteIfExists(path);
                        exchange.sendResponseHeaders(204, -1);
                        break;
                    case "PROPFIND":
                        String response = "<?xml version=\"1.0\" ?>"
                                + "<D:multistatus xmlns:D=\"DAV:\">"
                                + "<D:response><D:href>" + exchange.getRequestURI()
                                + "</D:href><D:propstat><D:prop><D:resourcetype/></D:prop>"
                                + "<D:status>HTTP/1.1 200 OK</D:status></D:propstat>"
                                + "</D:response></D:multistatus>";
                        byte[] bytes = response.getBytes("UTF-8");
                        exchange.getResponseHeaders().set("Content-Type", "application/xml; charset=utf-8");
                        exchange.sendResponseHeaders(207, bytes.length);
                        exchange.getResponseBody().write(bytes);
                        break;
                    default:
                        exchange.sendResponseHeaders(405, -1);
                        break;
                }
            } finally {
                exchange.getResponseBody().close();
            }
        });
        server.start();
        System.out.println("WebDAVサーバー起動: http://localhost:" + port + "/ (root: " + rootDir + ")");
    }
}

実行方法

java SimpleWebDavServer.java

テスト

PUTメソッドでファイルアップロード

curl -X PUT -T test.img http://localhost:8080/

GETメソッドでファイルダウンロード

curl -O http://localhost:8080/test.img 

DELETEメソッドでファイル削除

curl -X DELETE  http://localhost:8080/test.img

なんで作ったか

  • curlでsftp経由ファイルがやりとりしているけどどうも遅い
  • httpの方が暗号化してないからプライベートなマシン間ではこれくらいの浅いプロトコルでやった方が早いかなぁって
  • sftpとの速度比較はまだやってない
  • あとはJavaのソースファイルモードがめちゃくちゃ便利なので、Javaのペラ1ソースファイルでどこまで便利なツールが作れるか、という競技性が楽しい
  • ソースファイルモードでやってる限りは、設定ファイルなんていらなくて、ソースの上の方の初期値をちょっといじるだけでいい。楽しい。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?