/* http-cm - File management extensions to jdk.httpserver Copyright (C) 2021 Ulrich Hilger This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package de.uhilger.httpserver.cm; import com.sun.net.httpserver.Authenticator; import com.sun.net.httpserver.HttpExchange; import de.uhilger.httpserver.base.HttpResponder; import de.uhilger.httpserver.base.HttpHelper; import de.uhilger.httpserver.base.handler.FileHandler; import de.uhilger.httpserver.cm.actor.Lister; import de.uhilger.httpserver.cm.actor.Writer; import de.uhilger.httpserver.oauth.BearerAuthenticator; import java.io.IOException; /** *

Der FileManager verknuepft einen HTTP-Endpunkt mit einem Ordner des lokalen * Dateisystems.

* *

HTTP GET fuer eine Datei innerhalb dieses Ordners liefert den Dateiinhalt aus

* *

HTTP GET fuer einen Ordner liefert eine Liste von dessen Inhalt in JSON

* *

HTTP PUT fuer eine Datei ueberschreibt eine bestehende Datei mit dem im Body * uebergebenen Inhalt oder legt eine Datei mit diesem Inhalt an

* *

HTTP POST fuer eine Datei legt eine neue Datei mit dem im Body uebergebenen * Inhalt an oder erzeugt eine neue Datei mit einer laufenden Nummer, falls * diese Datei schon existiert

* *

HTTP POST fuer einen Ordner legt einen neuen Ordner an wenn er noch nicht * existiert oder erzeugt einen HTTP-Fehler 422

* *

HTTP DELETE loescht die Liste der Dateien und Ordner im Body

* *

HTTP PUT ?copyFrom=pfad kopiert die Liste der Datei- oder Ordnernamen im Body * der Anfrage vom Pfad in 'copyFrom' zum Pfad dieser Anfrage. Jede Datei, die * im Ziel bereits existiert, bekommt im Ziel einen neuen Namen mit einer * laufenden Nummer. Bei Ordnern, die im Ziel bereits existieren, bekommt der * betreffende Ordner im Ziel zunaechst einen neuen Namen mit einer laufenden * Nummer, dann wird der Quellordner ans Ziel kopiert.

* *

HTTP PUT ?moveFrom=pfad verschiebt die Liste der Datei- oder Ordnernamen im * Body der Anfrage vom Pfad in 'moveFrom' zum Pfad dieser Anfrage. Jede Datei, * die im Ziel bereits existiert, bekommt im Ziel einen neuen Namen mit einer * laufenden Nummer. Bei Ordnern, die im Ziel bereits existieren, bekommt der * betreffende Ordner im Ziel zunaechst einen neuen Namen mit einer laufenden * Nummer, dann wird der Quellordner ans Ziel kopiert.

* *

HTTP PUT mit ?duplicate legt eine Kopie der Datei an

* *

HTTP PUT mit '?renameTo=neuer Name' benennt die Datei oder den Ordner um, * sofern der neue Name noch nicht vergeben ist

* *

HTTP PUT mit '?zip' packt den Ordner

* *

HTTP PUT mit '?unzip' entpackt eine Datei

* *

Namenskonventionen:
* Ein Pfad mit Schraegstrich ('/') am Ende bezeichnet einen Ordner
* Ein Pfad ohne Schraegstrich ('/') am Ende bezeichnet eine Datei

* * @author Ulrich Hilger * @version 1, 13. Mai 2021 */ public class FileManager extends FileHandler { /* private static final String[] specialChars = {new String("\u00c4"), new String("\u00d6"), new String("\u00dc"), new String("\u00e4"), new String("\u00f6"), new String("\u00fc"), new String("\u00df")}; */ //public static final String UNWANTED_PATTERN = "[^a-zA-Z_0-9 ]"; /* HTTP Methoden */ public static final String UTF8 = "UTF-8"; public static final String STR_SLASH = "/"; public static final String STR_DOT = "."; public static final String P_COPY = "copyFrom"; public static final String P_MOVE = "moveFrom"; public static final String P_DUPLICATE = "duplicate"; public static final String P_RENAME = "renameTo"; public static final String P_ZIP = "zip"; public static final String P_UNZIP = "unzip"; public static final int OP_COPY = 1; public static final int OP_MOVE = 2; public static final int OP_DELETE = 3; public static final String ATTR_ROLE = "role"; @Override public void handle(HttpExchange e) throws IOException { Authenticator a = e.getHttpContext().getAuthenticator(); if(a instanceof BearerAuthenticator) { BearerAuthenticator auth = (BearerAuthenticator) a; //Realm realm = auth.getRealm(); String userId = e.getPrincipal().getUsername(); if(auth.hasRole(userId, e.getHttpContext().getAttributes().get(ATTR_ROLE).toString())) { String method = e.getRequestMethod(); //logger.fine("method: " + method); HttpHelper helper = new HttpHelper(); switch (method) { case HttpHelper.HTTP_GET: String path = e.getRequestURI().toString(); if (path.endsWith(STR_SLASH)) { String json = new Lister().liste(helper.getFileName(e), e.getHttpContext().getPath(), e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), path); if(null != json) { HttpResponder r = new HttpResponder(); r.antwortSenden(e, SC_OK, json); } else { emptyListResponse(e); } } else { new Lister().b64Action(helper.getFileName(e), e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString()); super.handle(e); } break; case HttpHelper.HTTP_PUT: new Writer().put(e, helper); break; case HttpHelper.HTTP_POST: new Writer().speichern(e, helper); break; case HttpHelper.HTTP_DELETE: new Writer().loeschen(e, helper); break; } } else { new Writer().standardHeaderUndAntwort(e, SC_FORBIDDEN, "Fehlende Rolle."); } } else { new Writer().standardHeaderUndAntwort(e, SC_FORBIDDEN, "Fehlende Rolle."); } } private void emptyListResponse(HttpExchange e) throws IOException { HttpResponder r = new HttpResponder(); String json = "{}"; //logger.log(Level.FINE, "json: ''{0}''", json); r.antwortSenden(e, SC_OK, json); } }