/*
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);
}
}