diff --git a/.gitignore b/.gitignore index 6143e53..e99d622 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,18 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* + +.idea/workspace.xml +.idea/**/gradle.xml +.idea/**/libraries +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries +.idea_modules/ diff --git a/.idea/artifacts/JDHttpApi_jar.xml b/.idea/artifacts/JDHttpApi_jar.xml new file mode 100644 index 0000000..9f8f958 --- /dev/null +++ b/.idea/artifacts/JDHttpApi_jar.xml @@ -0,0 +1,14 @@ + + + $PROJECT_DIR$/out/artifacts/JDHttpApi_jar + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..30b350b --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Core.xml b/.idea/libraries/Core.xml new file mode 100644 index 0000000..26fb12d --- /dev/null +++ b/.idea/libraries/Core.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..5755a99 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..eaf9e53 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/JDHttpApi.iml b/JDHttpApi.iml new file mode 100644 index 0000000..2cc930b --- /dev/null +++ b/JDHttpApi.iml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index ad42820..b3f455d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,127 @@ # JDHttpAPI JDownloader2 plugin with a local HTTP API to add new files for download + +This plugin is loaded by JDownloader2, which then starts up an embedded Jetty +HTTP server to receive + +From there, just about anything can send requests to queue up a new link. I +like to use [Tampermonkey userscripts](https://tampermonkey.net/) to scrape +links directly from web pages as I browse. + +Note: it binds to your IP address, therefore other PCs on the network can add +links. Configure a password or update the code to bind to something else - +there is not currently a way configure local-only access. This plugin also +accepts all Origins over ajax. + +## Install + +1. Close JDownloader. +2. Build or download the `JDHttpApi.jar` file. +3. Place that file in `./extensions/` inside the JDownloader2 program folder. +3. Open the file `./tmp/extensioncache/extensionInfos.json` in your JD program + folder and insert the following JSON as a new element in the array: + +``` +{ + "settings" : true, + "configInterface" : "org.jdownloader.extensions.httpAPI.HttpAPIConfig", + "quickToggle" : false, + "headlessRunnable" : true, + "description" : "Http API.", + "lng" : "en_US", + "iconPath" : "folder_add", + "linuxRunnable" : true, + "macRunnable" : true, + "name" : "HTTP API", + "version" : -1, + "windowsRunnable" : true, + "classname" : "org.jdownloader.extensions.httpAPI.HttpAPIExtension", + "jarPath" : "/absolute/path/to/jd2/extensions/JDHttpApi.jar" +} +``` + +4. Open the file `./update/versioninfo/JD/extensions.installed.json` inside the + JD program folder and insert the string `"jdhttpapi"` as the last element + in the JSON array. +5. Start JDownloader2 and go to the settings page to enable the extension. + +Note: there is no official extension install process, so most of this is +tricking JD into thinking the JAR is already installed. It's possible that +an update will trigger a cache invalidation that boots out this extension. Just +reapply the steps above and you should get it back. + +## Configure + +This plugin has four settings to configure through the JDownloader GUI. In order +to make changes take effect, disable and then re-enable the extension. + +1. Use a password: require password authentication. +2. Port: the port that the HTTP server listens on. Defaults to 8297. +3. Password: If you've enabled the password feature, set it here. +4. Allow Get: This disables HTTP GET access to the API. When enabled, you + must POST new links as JSON. This can help you reduce exposure to CSRF + vulnerabilities, especially when combined with a password. + +## Use + +There is currently only one URL: `/addLink`. You may submit via POST or GET. + +### GET Service + +There are three parameters, only `url` is required: + +* `url`: The URL to add. +* `packageName`: If you want to configure a custom package name, send it here. +* `forcePackageName`: Set this to `true` to set the package name. For whatever + reason, this is a separate field in JD's internals but if you don't force + it, the package name will not be changed. It's possible I am hooking in too + late in the process. + +The response has three possible values: + +On success: `{"success":true}` +On malformed input: `{"errorMessage":"some error message"}` +On authentication failure: `Login to access API` (this is not JSON) + +CURL Examples: + +``` +curl 'http://localhost:8297/addLink?url=https://i.imgur.com/muChjiN.jpg' +curl 'http://localhost:8297/addLink?url=https://i.imgur.com/muChjiN.jpg&packageName=cutebunny&forcePackageName=true' +``` + +### POST Service + +Send a JSON object via POST with the same values as in the GET request: + +``` +curl -X POST 'http://localhost:8297/addLink' \ + -d '{"url":"https://i.imgur.com/muChjiN.jpg"}' +curl -X POST 'http://localhost:8297/addLink' \ + -d '{"url":"https://i.imgur.com/muChjiN.jpg","packageName":"cutebunny","forcePackageName":true}' +``` + +### Authentication + +If you choose to use a password, send it as the password portion of HTTP Basic +Authentication - leave the username blank. + +CURL Example: + +``` +curl -u ':mypassword' 'http://192.168.1.7:8297/addLink?url=https://i.imgur.com/muChjiN.jpg' +curl -u ':mypassword' -X POST 'http://localhost:8297/addLink' \ + -d '{"url":"https://i.imgur.com/muChjiN.jpg"}' +``` + +## Errata + +JDownloader2's extension system is surprisingly +modular and easy to understand (aside from the install process). Feel free to +use this project as an example for building other JD extensions as even the +built-in ones are a bit more complex than this. Just make sure to have +[the source code](https://svn.jdownloader.org/projects/jd) open up in +another window for reference - there is virtually no documentation available +and this project only uses the bare minimum of features. + + diff --git a/lib/Core.jar b/lib/Core.jar new file mode 100644 index 0000000..c8022fd Binary files /dev/null and b/lib/Core.jar differ diff --git a/lib/JDGUI.jar b/lib/JDGUI.jar new file mode 100644 index 0000000..57a0f90 Binary files /dev/null and b/lib/JDGUI.jar differ diff --git a/lib/JDownloader.jar b/lib/JDownloader.jar new file mode 100644 index 0000000..9505d39 Binary files /dev/null and b/lib/JDownloader.jar differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..29db9b6 --- /dev/null +++ b/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + jdownloaderPlugins + JDownloaderPlugins + 1.0-SNAPSHOT + + + + org.eclipse.jetty + jetty-server + 9.4.7.v20170914 + + +     com.google.code.gson +     gson +     2.8.2 + + + + \ No newline at end of file diff --git a/settings-screenshot.png b/settings-screenshot.png new file mode 100644 index 0000000..a67b471 Binary files /dev/null and b/settings-screenshot.png differ diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000..f971d52 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +Class-Path: jetty-io-9.4.7.v20170914.jar jetty-server-9.4.7.v20170914. + jar Core.jar JDownloader.jar JDGUI.jar gson-2.8.2.jar jetty-http-9.4. + 7.v20170914.jar javax.servlet-api-3.1.0.jar jetty-util-9.4.7.v2017091 + 4.jar + diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/CFG_HTTPAPI.java b/src/main/java/org/jdownloader/extensions/httpAPI/CFG_HTTPAPI.java new file mode 100644 index 0000000..ab175a0 --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/CFG_HTTPAPI.java @@ -0,0 +1,29 @@ +package org.jdownloader.extensions.httpAPI; + +import org.appwork.storage.config.handler.BooleanKeyHandler; +import org.appwork.storage.config.handler.IntegerKeyHandler; +import org.appwork.storage.config.handler.StorageHandler; +import org.appwork.storage.config.handler.StringKeyHandler; +import org.appwork.utils.Application; +import org.appwork.storage.config.ConfigUtils; +import org.appwork.storage.config.JsonConfig; + +public class CFG_HTTPAPI { + public static void main(String[] args) { + ConfigUtils.printStaticMappings(HttpAPIConfig.class, "Application.getResource(\"cfg/\" + " + HttpAPIExtension.class.getSimpleName() + ".class.getName())"); + } + + public static final HttpAPIConfig CFG = JsonConfig.create(Application.getResource("cfg/" + HttpAPIExtension.class.getName()), HttpAPIConfig.class); + + public static final StorageHandler SH = (StorageHandler) CFG._getStorageHandler(); + + public static final BooleanKeyHandler ENABLED = SH.getKeyHandler("Enabled", BooleanKeyHandler.class); + + public static final IntegerKeyHandler PORT = SH.getKeyHandler("Port", IntegerKeyHandler.class); + + public static final BooleanKeyHandler ALLOW_GET = SH.getKeyHandler("AllowGet", BooleanKeyHandler.class); + + public static final BooleanKeyHandler USE_PASSWORD = SH.getKeyHandler("UsePassword", BooleanKeyHandler.class); + + public static final StringKeyHandler PASSWORD = SH.getKeyHandler("Password", StringKeyHandler.class); +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPIConfig.java b/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPIConfig.java new file mode 100644 index 0000000..09e271b --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPIConfig.java @@ -0,0 +1,28 @@ +package org.jdownloader.extensions.httpAPI; + +import jd.plugins.ExtensionConfigInterface; +import org.appwork.storage.config.annotations.AboutConfig; +import org.appwork.storage.config.annotations.DefaultBooleanValue; +import org.appwork.storage.config.annotations.DefaultIntValue; + +public interface HttpAPIConfig extends ExtensionConfigInterface { + + @AboutConfig + @DefaultIntValue(8297) + int getPort(); + void setPort(int port); + + @AboutConfig + @DefaultBooleanValue(false) + boolean getAllowGet(); + void setAllowGet(boolean enabled); + + @AboutConfig + @DefaultBooleanValue(false) + boolean getUsePassword(); + void setUsePassword(boolean enabled); + + @AboutConfig + String getPassword(); + void setPassword(String password); +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPIConfigPanel.java b/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPIConfigPanel.java new file mode 100644 index 0000000..17e38a6 --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPIConfigPanel.java @@ -0,0 +1,31 @@ +package org.jdownloader.extensions.httpAPI; + + +import org.jdownloader.extensions.ExtensionConfigPanel; + +import jd.gui.swing.jdgui.views.settings.panels.advanced.AdvancedConfigTableModel; +import jd.gui.swing.jdgui.views.settings.panels.advanced.AdvancedTable; + +public class HttpAPIConfigPanel extends ExtensionConfigPanel { + + private AdvancedConfigTableModel model; + + public HttpAPIConfigPanel(HttpAPIExtension extension){ + super(extension); + + add(new AdvancedTable(model= new AdvancedConfigTableModel("HttpAPIConfigPanel"){ + @Override + public void refresh(String filterText){ _fireTableStructureChanged(register(), true);} + })); + model.refresh("HttpAPIConfigPanel"); + } + + @Override + public void save() { + } + + @Override + public void updateContents() { + + } +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPIExtension.java b/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPIExtension.java new file mode 100644 index 0000000..b7dafb0 --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPIExtension.java @@ -0,0 +1,125 @@ +package org.jdownloader.extensions.httpAPI; + +import jd.controlling.linkcollector.LinkCollector; +import org.appwork.storage.config.ValidationException; +import org.appwork.utils.Application; +import jd.plugins.AddonPanel; +import org.appwork.storage.config.events.GenericConfigEventListener; +import org.appwork.storage.config.handler.KeyHandler; +import org.appwork.utils.logging2.LogSource; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.HandlerList; +import org.jdownloader.extensions.AbstractExtension; +import org.jdownloader.extensions.StartException; +import org.jdownloader.extensions.StopException; +import org.jdownloader.extensions.httpAPI.handlers.AjaxHandler; +import org.jdownloader.extensions.httpAPI.handlers.AuthorizationHandler; +import org.jdownloader.extensions.httpAPI.handlers.JDServerGETHandler; +import org.jdownloader.extensions.httpAPI.handlers.JDServerPOSTHandler; +import org.jdownloader.gui.IconKey; +import org.jdownloader.logging.LogController; + +import java.util.logging.Level; +import java.util.logging.LogRecord; + +public class HttpAPIExtension extends AbstractExtension implements Runnable, GenericConfigEventListener { + private LogSource logger; + private HttpAPIConfigPanel configPanel; + private Server server; + + @Override + protected void initExtension() throws StartException { + logger = LogController.CL(HttpAPIExtension.class); + if (!Application.isHeadless()) { + configPanel = new HttpAPIConfigPanel(this); + } + } + + @Override + protected void start() throws StartException { + CFG_HTTPAPI.PORT.getEventSender().addListener(this, true); + startServer(); + } + + protected void stop() throws StopException { + //ContainerPluginController.getInstance().remove(plugin.getAndSet(null)); + stopServer(); + } + + @Override + public String getIconKey() { + return IconKey.ICON_FOLDER_ADD; + } + + + public void run() { + startServer(); + } + + @Override + public boolean isHeadlessRunnable() { + return true; + } + + @Override + public boolean hasConfigPanel() { + return true; + } + + @Override + public HttpAPIConfigPanel getConfigPanel() { + return configPanel; + } + + @Override + public AddonPanel getGUI() { + return null; + } + + @Override + public String getDescription() { + return T.description(); + } + + public void onConfigValidatorError(KeyHandler keyHandler, Integer invalidValue, ValidationException validateException) { + } + + public synchronized void onConfigValueModified(KeyHandler keyHandler, Integer newValue) { + stopServer(); + startServer(); + } + + private void startServer() { + HttpAPIConfig cfg = getSettings(); + server = new Server(cfg.getPort()); + HandlerList lst = new HandlerList(); + LinkController ctr = new JDLinkController(LinkCollector.getInstance()); + if(cfg.getUsePassword() && cfg.getPassword() != null && !cfg.getPassword().equals("")) { + lst.addHandler(new AuthorizationHandler(cfg.getPassword())); + } + lst.addHandler(new AjaxHandler(cfg.getAllowGet())); + if(cfg.getAllowGet()) { + lst.addHandler(new JDServerGETHandler(ctr)); + } + lst.addHandler(new JDServerPOSTHandler(ctr)); + server.setHandler(lst); + try { + server.start(); + } + catch(Exception e) { + logger.log(new LogRecord(Level.SEVERE, e.getMessage())); + } + } + + private void stopServer() { + if(server != null) { + try { + server.stop(); + } + catch(Exception e) { + logger.log(new LogRecord(Level.SEVERE, e.getMessage())); + } + } + server = null; + } +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPITranslation.java b/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPITranslation.java new file mode 100644 index 0000000..7c8ff61 --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/HttpAPITranslation.java @@ -0,0 +1,14 @@ +package org.jdownloader.extensions.httpAPI; + +import org.appwork.txtresource.Default; +import org.appwork.txtresource.Defaults; +import org.appwork.txtresource.TranslateInterface; + +@Defaults(lngs = { "en" }) +public interface HttpAPITranslation extends TranslateInterface { + @Default(lngs = { "en" }, values = { "HTTP API" }) + String title(); + + @Default(lngs = { "en" }, values = { "Bundled HTTP server to add new files" }) + String description(); +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/JDLinkController.java b/src/main/java/org/jdownloader/extensions/httpAPI/JDLinkController.java new file mode 100644 index 0000000..cf20627 --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/JDLinkController.java @@ -0,0 +1,28 @@ +package org.jdownloader.extensions.httpAPI; + +import jd.controlling.linkcollector.LinkCollectingJob; +import jd.controlling.linkcollector.LinkCollector; +import jd.controlling.linkcollector.LinkOrigin; +import jd.controlling.linkcollector.LinkOriginDetails; +import jd.controlling.linkcrawler.CrawledLink; +import jd.controlling.linkcrawler.CrawledLinkModifier; +import jd.controlling.linkcrawler.modifier.PackageNameModifier; + +public class JDLinkController implements LinkController { + private LinkCollector collector; + + public JDLinkController(LinkCollector collector){ + this.collector = collector; + } + + public void AddLink(String url) { + LinkCollectingJob job = new LinkCollectingJob(LinkOriginDetails.getInstance(LinkOrigin.EXTENSION, "HTTPAPI"), url); + collector.addCrawlerJob(job); + } + + public void AddLink(String url, String packageName, boolean forcePackageName) { + LinkCollectingJob job = new LinkCollectingJob(LinkOriginDetails.getInstance(LinkOrigin.EXTENSION, "HTTPAPI"), url); + job.addPostPackagizerModifier(new PackageNameModifier(packageName, forcePackageName)); + collector.addCrawlerJob(job); + } +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/LinkController.java b/src/main/java/org/jdownloader/extensions/httpAPI/LinkController.java new file mode 100644 index 0000000..8039b04 --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/LinkController.java @@ -0,0 +1,8 @@ +package org.jdownloader.extensions.httpAPI; + +public interface LinkController { + + public void AddLink(String url); + + public void AddLink(String url, String packageName, boolean forcePackageName); +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/ParseException.java b/src/main/java/org/jdownloader/extensions/httpAPI/ParseException.java new file mode 100644 index 0000000..189b8f0 --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/ParseException.java @@ -0,0 +1,7 @@ +package org.jdownloader.extensions.httpAPI; + +public class ParseException extends Exception{ + public ParseException(String message) { + super(message); + } +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/handlers/AjaxHandler.java b/src/main/java/org/jdownloader/extensions/httpAPI/handlers/AjaxHandler.java new file mode 100644 index 0000000..92b6387 --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/handlers/AjaxHandler.java @@ -0,0 +1,39 @@ +package org.jdownloader.extensions.httpAPI.handlers; + +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class AjaxHandler extends AbstractHandler { + private final boolean allowGet; + + public AjaxHandler(boolean allowGet) { + this.allowGet = allowGet; + } + + public void handle(String target, + Request baseRequest, + HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + if(baseRequest.getMethod().equals("OPTIONS")) { + + response.setStatus(HttpServletResponse.SC_OK); + response.setHeader("Access-Control-Allow-Origin", "*"); + + String methods = "POST, OPTIONS"; + if(allowGet) methods += ", GET"; + response.setHeader("Access-Control-Allow-Methods", methods); + response.setHeader("Access-Control-Max-Age", "1000"); + String req = request.getHeader("Access-Control-Request-Headers"); + if(req != null) { + response.setHeader("Access-Control-Allow-Headers", req); + } + + baseRequest.setHandled(true); + } + } +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/handlers/AuthorizationHandler.java b/src/main/java/org/jdownloader/extensions/httpAPI/handlers/AuthorizationHandler.java new file mode 100644 index 0000000..383dd57 --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/handlers/AuthorizationHandler.java @@ -0,0 +1,38 @@ +package org.jdownloader.extensions.httpAPI.handlers; + +import org.appwork.utils.encoding.Base64; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +public class AuthorizationHandler extends AbstractHandler { + private final String password; + private final String authenticationHeader; + + public AuthorizationHandler(String password) { + this.password = password; + authenticationHeader = "Basic " + Base64.encode(":" + password); + } + + public void handle(String target, + Request baseRequest, + HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + String header = request.getHeader("Authorization"); + if(header == null || !header.equals(authenticationHeader)) { + response.addHeader("WWW-Authenticate", "Basic"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + + response.setContentType("text/plain; charset=utf-8"); + PrintWriter out = response.getWriter(); + out.println("Login to access API"); + + baseRequest.setHandled(true); + } + } +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/handlers/BaseHandler.java b/src/main/java/org/jdownloader/extensions/httpAPI/handlers/BaseHandler.java new file mode 100644 index 0000000..8005d6b --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/handlers/BaseHandler.java @@ -0,0 +1,89 @@ +package org.jdownloader.extensions.httpAPI.handlers; + +import com.google.gson.Gson; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.jdownloader.extensions.httpAPI.LinkController; +import org.jdownloader.extensions.httpAPI.models.AddLinkRequest; +import org.jdownloader.extensions.httpAPI.models.AddLinkResponse; +import org.jdownloader.extensions.httpAPI.ParseException; +import org.jdownloader.extensions.httpAPI.models.ErrorResponse; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +public abstract class BaseHandler extends AbstractHandler { + + protected final Gson jparser = new Gson(); + + protected final LinkController controller; + + protected BaseHandler(LinkController ctr) { + super(); + controller = ctr; + } + + protected abstract AddLinkRequest parseAddLinkParams(HttpServletRequest req) throws ParseException; + + protected abstract String getAllowedMethod(); + + private void writeResponse(Request baseRequest, HttpServletResponse response, Object data) throws IOException{ + response.setStatus(HttpServletResponse.SC_OK); + response.setContentType("application/json; charset=utf-8"); + + String origin = baseRequest.getHeader("Origin"); + if(origin != null) { + response.setHeader("Access-Control-Allow-Origin", origin); + } + + PrintWriter out = response.getWriter(); + out.println(jparser.toJson(data)); + baseRequest.setHandled(true); + } + + private void writeError(Request baseRequest, HttpServletResponse response, String message) throws IOException{ + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.setContentType("application/json; charset=utf-8"); + ErrorResponse resp = new ErrorResponse(); + resp.errorMessage = message; + PrintWriter out = response.getWriter(); + out.println(jparser.toJson(resp)); + baseRequest.setHandled(true); + } + + public void handle(String target, + Request baseRequest, + HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + if(!baseRequest.getMethod().equals(getAllowedMethod())) { + return; + } + + String path = request.getPathInfo(); + + if(path.equals("/addLink")) { + AddLinkRequest data; + try { + data = parseAddLinkParams(request); + } + catch (ParseException e) { + writeError(baseRequest, response, e.getMessage()); + return; + } + + if(data.packageName != null && !data.packageName.equals("")) { + controller.AddLink(data.url.toString(), data.packageName, data.forcePackageName); + } + else { + controller.AddLink(data.url.toString()); + } + + AddLinkResponse resp = new AddLinkResponse(); + resp.success = true; + writeResponse(baseRequest, response, resp); + } + } +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/handlers/JDServerGETHandler.java b/src/main/java/org/jdownloader/extensions/httpAPI/handlers/JDServerGETHandler.java new file mode 100644 index 0000000..069a08f --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/handlers/JDServerGETHandler.java @@ -0,0 +1,49 @@ +package org.jdownloader.extensions.httpAPI.handlers; + + +import org.jdownloader.extensions.httpAPI.LinkController; +import org.jdownloader.extensions.httpAPI.models.AddLinkRequest; +import org.jdownloader.extensions.httpAPI.ParseException; + +import javax.servlet.http.HttpServletRequest; +import java.net.MalformedURLException; +import java.net.URL; + + +public class JDServerGETHandler extends BaseHandler { + + public JDServerGETHandler(LinkController ctr) { + super(ctr); + } + + protected AddLinkRequest parseAddLinkParams(HttpServletRequest req) throws ParseException{ + AddLinkRequest data = new AddLinkRequest(); + + try { + URL url = new URL(req.getParameter("url")); + if (url == null || url.equals("")) { + throw new ParseException("Missing parameter 'url'"); + } + data.url = url; + } + catch(MalformedURLException e) { + throw new ParseException("Parameter 'url' is malformed"); + } + + String pkg = req.getParameter("packageName"); + if(pkg != null && !pkg.equals("")) { + data.packageName = pkg; + } + + String force = req.getParameter("forcePackageName"); + if(force != null && force.equals("true")) { + data.forcePackageName = true; + } + + return data; + } + + protected String getAllowedMethod() { + return "GET"; + } +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/handlers/JDServerPOSTHandler.java b/src/main/java/org/jdownloader/extensions/httpAPI/handlers/JDServerPOSTHandler.java new file mode 100644 index 0000000..4f143ad --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/handlers/JDServerPOSTHandler.java @@ -0,0 +1,39 @@ +package org.jdownloader.extensions.httpAPI.handlers; + + +import com.google.gson.JsonSyntaxException; +import org.jdownloader.extensions.httpAPI.LinkController; +import org.jdownloader.extensions.httpAPI.ParseException; +import org.jdownloader.extensions.httpAPI.models.AddLinkRequest; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +public class JDServerPOSTHandler extends BaseHandler { + + public JDServerPOSTHandler(LinkController ctr) { + super(ctr); + } + + protected AddLinkRequest parseAddLinkParams(HttpServletRequest req) throws ParseException{ + try { + AddLinkRequest data = jparser.fromJson(req.getReader(), AddLinkRequest.class); + + if (data.url == null || data.url.equals("")) { + throw new ParseException("Missing parameter 'url'"); + } + + return data; + } + catch(IOException e) { + throw new ParseException(e.getMessage()); + } + catch(JsonSyntaxException e) { + throw new ParseException(e.getMessage()); + } + } + + protected String getAllowedMethod() { + return "POST"; + } +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/models/AddLinkRequest.java b/src/main/java/org/jdownloader/extensions/httpAPI/models/AddLinkRequest.java new file mode 100644 index 0000000..290c3b5 --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/models/AddLinkRequest.java @@ -0,0 +1,12 @@ +package org.jdownloader.extensions.httpAPI.models; + +import java.net.URL; + +public class AddLinkRequest { + + public URL url; + + public String packageName = null; + + public boolean forcePackageName = false; +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/models/AddLinkResponse.java b/src/main/java/org/jdownloader/extensions/httpAPI/models/AddLinkResponse.java new file mode 100644 index 0000000..4c6afa2 --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/models/AddLinkResponse.java @@ -0,0 +1,7 @@ +package org.jdownloader.extensions.httpAPI.models; + +public class AddLinkResponse { + public boolean success; + + public String errorMessage; +} diff --git a/src/main/java/org/jdownloader/extensions/httpAPI/models/ErrorResponse.java b/src/main/java/org/jdownloader/extensions/httpAPI/models/ErrorResponse.java new file mode 100644 index 0000000..cdbf80d --- /dev/null +++ b/src/main/java/org/jdownloader/extensions/httpAPI/models/ErrorResponse.java @@ -0,0 +1,5 @@ +package org.jdownloader.extensions.httpAPI.models; + +public class ErrorResponse { + public String errorMessage; +} diff --git a/src/main/java/org/jdownloader/sample/Program.java b/src/main/java/org/jdownloader/sample/Program.java new file mode 100644 index 0000000..7b3ba84 --- /dev/null +++ b/src/main/java/org/jdownloader/sample/Program.java @@ -0,0 +1,36 @@ +package org.jdownloader.sample; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.HandlerList; +import org.jdownloader.extensions.httpAPI.LinkController; +import org.jdownloader.extensions.httpAPI.handlers.AjaxHandler; +import org.jdownloader.extensions.httpAPI.handlers.AuthorizationHandler; +import org.jdownloader.extensions.httpAPI.handlers.JDServerGETHandler; +import org.jdownloader.extensions.httpAPI.handlers.JDServerPOSTHandler; + + +public class Program { + public static void main(String[] args) { + int port = 8297; + HandlerList lst = new HandlerList(); + + String password = null;//"pass"; + Server server = new Server(port); + JDServerPOSTHandler hnd; + LinkController ctr = new SampleLinkController(); + if(password != null) { + lst.addHandler(new AuthorizationHandler(password)); + } + lst.addHandler(new AjaxHandler(true)); + lst.addHandler(new JDServerGETHandler(ctr)); + lst.addHandler(new JDServerPOSTHandler(ctr)); + server.setHandler(lst); + try { + server.start(); + server.join(); + } + catch(Exception e) { + System.out.println(e); + } + } +} diff --git a/src/main/java/org/jdownloader/sample/SampleLinkController.java b/src/main/java/org/jdownloader/sample/SampleLinkController.java new file mode 100644 index 0000000..3e6fff3 --- /dev/null +++ b/src/main/java/org/jdownloader/sample/SampleLinkController.java @@ -0,0 +1,18 @@ +package org.jdownloader.sample; + +import org.jdownloader.extensions.httpAPI.LinkController; + +public class SampleLinkController implements LinkController { + public void AddLink(String url) { + System.out.println("Adding URL " + url); + } + + public void AddLink(String url, String packageName, boolean forcePackageName) { + if(forcePackageName) { + System.out.println("Adding URL " + url + " with forced package " + packageName); + } + else { + System.out.println("Adding URL " + url + " in package " + packageName); + } + } +}