From ddb1a8773ed6aa8e6676194a79cbe09c2b54cc46 Mon Sep 17 00:00:00 2001 From: Toby Chui Date: Fri, 30 May 2025 15:57:59 +0800 Subject: [PATCH] Added restful-api plugin - Added restful-api example plugin - Added more plugin docs - Added zoraxy_plugin HandleFunc API --- .gitignore | 1 + .../docs/2. Architecture/5. Plugin UI.md | 2 +- .../docs/3. Basic Examples/1. Hello World.md | 4 + .../3. Basic Examples/2. RESTful Example.md | 493 +++++++++++ .../image-20250530134148399.png | Bin 0 -> 37466 bytes .../image-20250530153148506.png | Bin 0 -> 58979 bytes docs/plugins/docs/index.md | 12 +- .../1. What is Zoraxy Plugin.html | 3 + .../1. Introduction/2. Getting Started.html | 3 + .../1. Introduction/3. Installing Plugin.html | 3 + .../1. Introduction/4. Enable Plugins.html | 3 + .../1. Plugin Architecture.html | 3 + .../html/2. Architecture/2. Introspect.html | 3 + .../html/2. Architecture/3. Configure.html | 3 + .../2. Architecture/4. Capture Modes.html | 3 + .../html/2. Architecture/5. Plugin UI.html | 5 +- .../3. Basic Examples/1. Hello World.html | 8 + .../3. Basic Examples/2. RESTful Example.html | 787 ++++++++++++++++++ .../image-20250530134148399.png | Bin 0 -> 37466 bytes .../image-20250530153148506.png | Bin 0 -> 58979 bytes docs/plugins/html/index.html | 23 + docs/plugins/index.html | 2 +- docs/plugins/index.json | 5 + docs/plugins/main.go | 2 +- example/plugins/restful-example/go.mod | 3 + example/plugins/restful-example/icon.png | Bin 0 -> 14120 bytes example/plugins/restful-example/main.go | 103 +++ .../mod/zoraxy_plugin/README.txt | 19 + .../mod/zoraxy_plugin/dev_webserver.go | 145 ++++ .../mod/zoraxy_plugin/dynamic_router.go | 162 ++++ .../mod/zoraxy_plugin/embed_webserver.go | 174 ++++ .../mod/zoraxy_plugin/static_router.go | 105 +++ .../mod/zoraxy_plugin/zoraxy_plugin.go | 176 ++++ .../plugins/restful-example/www/index.html | 126 +++ 34 files changed, 2376 insertions(+), 5 deletions(-) create mode 100644 docs/plugins/docs/3. Basic Examples/2. RESTful Example.md create mode 100644 docs/plugins/docs/3. Basic Examples/img/1. Hello World/image-20250530134148399.png create mode 100644 docs/plugins/docs/3. Basic Examples/img/2. RESTful Example/image-20250530153148506.png create mode 100644 docs/plugins/html/3. Basic Examples/2. RESTful Example.html create mode 100644 docs/plugins/html/3. Basic Examples/img/1. Hello World/image-20250530134148399.png create mode 100644 docs/plugins/html/3. Basic Examples/img/2. RESTful Example/image-20250530153148506.png create mode 100644 example/plugins/restful-example/go.mod create mode 100644 example/plugins/restful-example/icon.png create mode 100644 example/plugins/restful-example/main.go create mode 100644 example/plugins/restful-example/mod/zoraxy_plugin/README.txt create mode 100644 example/plugins/restful-example/mod/zoraxy_plugin/dev_webserver.go create mode 100644 example/plugins/restful-example/mod/zoraxy_plugin/dynamic_router.go create mode 100644 example/plugins/restful-example/mod/zoraxy_plugin/embed_webserver.go create mode 100644 example/plugins/restful-example/mod/zoraxy_plugin/static_router.go create mode 100644 example/plugins/restful-example/mod/zoraxy_plugin/zoraxy_plugin.go create mode 100644 example/plugins/restful-example/www/index.html diff --git a/.gitignore b/.gitignore index d8f7c63..237de3b 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,4 @@ example/plugins/ztnc/ztnc.db example/plugins/ztnc/authtoken.secret example/plugins/ztnc/ztnc.db.lock docs/plugins/docs.exe +*.exe \ No newline at end of file diff --git a/docs/plugins/docs/2. Architecture/5. Plugin UI.md b/docs/plugins/docs/2. Architecture/5. Plugin UI.md index b4e64b4..6fe321c 100644 --- a/docs/plugins/docs/2. Architecture/5. Plugin UI.md +++ b/docs/plugins/docs/2. Architecture/5. Plugin UI.md @@ -6,7 +6,7 @@ Last Update: 25/05/2025 A plugin can optionally expose a Web UI interface for user configuration. -**It is generally recommended that a plugin have such UI exposed for easy configurations.** As plugin installed via plugin store provides limited ways for a user to configure the plugin, the plugin web UI will be the best way for user to setup your plugin. +**A plugin must provide a UI, as it is part of the control mechanism of the plugin life cycle. (i.e. Zoraxy use the plugin UI HTTP server to communicate with the plugin for control signals)** As plugin installed via plugin store provides limited ways for a user to configure the plugin, the plugin web UI will be the best way for user to setup your plugin. ## Plugin Web UI Access diff --git a/docs/plugins/docs/3. Basic Examples/1. Hello World.md b/docs/plugins/docs/3. Basic Examples/1. Hello World.md index 6729085..31edae5 100644 --- a/docs/plugins/docs/3. Basic Examples/1. Hello World.md +++ b/docs/plugins/docs/3. Basic Examples/1. Hello World.md @@ -121,6 +121,8 @@ And here is an example `index.html` file that uses the Zoraxy internal resources ``` + + --- ## 6. Creating a handler for Introspect @@ -240,6 +242,8 @@ After saving the `main.go` file, you can now build your plugin with `go build`. After you are done, restart Zoraxy and enable your plugin in the Plugin List. Now you can test and debug your plugin with your HTTP Proxy Rules. All the STDOUT and STDERR of your plugin will be forwarded to the STDOUT of Zoraxy as well as the log file. +![image-20250530134148399](img/1. Hello World/image-20250530134148399.png) + **Tips** diff --git a/docs/plugins/docs/3. Basic Examples/2. RESTful Example.md b/docs/plugins/docs/3. Basic Examples/2. RESTful Example.md new file mode 100644 index 0000000..5a2a5c8 --- /dev/null +++ b/docs/plugins/docs/3. Basic Examples/2. RESTful Example.md @@ -0,0 +1,493 @@ +# RESTful API Call in Web UI +Last Update: 29/05/2025 + +--- + +When developing a UI for your plugin, sometime you might need to make RESTFUL API calls to your plugin backend for setting up something or getting latest information from your plugin. In this example, I will show you how to create a plugin with RESTful api call capabilities with the embedded web server and the custom `cjax` function. + +**Notes: This example assumes you have basic understanding on how to use jQuery `ajax` request.** + +Lets get started! + +--- + +## 1. Create the plugin folder structures + +This step is identical to the Hello World example, where you create a plugin folder with the required go project structure in the folder. Please refer to the Hello World example section 1 to 5 for details. + +--- + +## 2. Create Introspect + +This is quite similar to the Hello World example as well, but we are changing some of the IDs to match what we want to do in this plugin. + +```go +runtimeCfg, err := plugin.ServeAndRecvSpec(&plugin.IntroSpect{ + ID: "com.example.restful-example", + Name: "Restful Example", + Author: "foobar", + AuthorContact: "admin@example.com", + Description: "A simple demo for making RESTful API calls in plugin", + URL: "https://example.com", + Type: plugin.PluginType_Utilities, + VersionMajor: 1, + VersionMinor: 0, + VersionPatch: 0, + + // As this is a utility plugin, we don't need to capture any traffic + // but only serve the UI, so we set the UI (relative to the plugin path) to "/" + UIPath: UI_PATH, + }) + if err != nil { + //Terminate or enter standalone mode here + panic(err) + } +``` + +--- + +## 3. Create an embedded web server with handlers + +In this step, we create a basic embedded web file handler similar to the Hello World example, however, we will need to add a `http.HandleFunc` to the plugin so our front-end can request and communicate with the backend. + +```go +embedWebRouter := plugin.NewPluginEmbedUIRouter(PLUGIN_ID, &content, WEB_ROOT, UI_PATH) +embedWebRouter.RegisterTerminateHandler(func() { + fmt.Println("Restful-example Exited") +}, nil) + +//Register a simple API endpoint that will echo the request body +// Since we are using the default http.ServeMux, we can register the handler directly with the last +// parameter as nil +embedWebRouter.HandleFunc("/api/echo", func(w http.ResponseWriter, r *http.Request) { + //Some handler code here +}, nil) +``` + +The `embedWebRouter.HandleFunc` last parameter is the `http.Mux`, where if you have multiple web server listening interface, you can fill in different Mux based on your implementation. On of the examples is that, when you are developing a static web server plugin, where you need a dedicated HTTP listening endpoint that is not the one Zoraxy assigned to your plugin, you need to create two http.Mux and assign one of them for Zoraxy plugin UI purpose. + +--- + +## 4. Modify the front-end HTML file to make request to backend + +To make a RESTFUL API to your plugin, **you must use relative path in your request URL**. + +Absolute path that start with `/` is only use for accessing Zoraxy resouces. For example, when you access `/img/logo.svg`, Zoraxy webmin HTTP router will return the logo of Zoraxy for you instead of `/plugins/your_plugin_name/{your_web_root}/img/logo.svg`. + +### Making GET request + +Making GET request is similar to what you would do in ordinary web development, but only limited to relative paths like `./api/foo/bar` instead. Here is an example on a front-end and back-end implementation of a simple "echo" API. + +The API logic is simple: when you make a GET request to the API with `?name=foobar`, it returns `Hello foobar`. Here is the backend implementation in your plugin code. + +```go +embedWebRouter.HandleFunc("/api/echo", func(w http.ResponseWriter, r *http.Request) { + // This is a simple echo API that will return the request body as response + name := r.URL.Query().Get("name") + if name == "" { + http.Error(w, "Missing 'name' query parameter", http.StatusBadRequest) + return + } + w.Header().Set("Content-Type", "application/json") + response := map[string]string{"message": fmt.Sprintf("Hello %s", name)} + if err := json.NewEncoder(w).Encode(response); err != nil { + http.Error(w, "Failed to encode response", http.StatusInternalServerError) + } + }, nil) +``` + +And here is the front-end code in your HTML file + +```html + +

Echo Test (HTTP GET)

+
+
+ + +
+ + +
+ + +``` + + + +### Making POST request + +Making POST request is also similar to GET request, except when making the request, you will need pass the CSRF-Token with the payload. This is required due to security reasons (See [#267](https://github.com/tobychui/zoraxy/issues/267) for more details). + +Since the CSRF validation is done by Zoraxy, your plugin backend code can be implemented just like an ordinary handler. Here is an example POST handling function that receive a FORM POST and print it in an HTML response. + +```go +embedWebRouter.HandleFunc("/api/post", func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + if err := r.ParseForm(); err != nil { + http.Error(w, "Failed to parse form data", http.StatusBadRequest) + return + } + + for key, values := range r.PostForm { + for _, value := range values { + // Generate a simple HTML response + w.Header().Set("Content-Type", "text/html") + fmt.Fprintf(w, "%s: %s
", key, value) + } + } +}, nil) + +``` + +For the front-end, you will need to use the `$.cjax` function implemented in Zoraxy `utils.js` file. You can include this file by adding these two lines to your HTML file. + +```html + + + + +

Form Post Test (HTTP POST)

+
+
+ + +
+
+ + +
+
+ +
+ + +
+
+ + +
+
+ + +
+``` + +After that, you can call to the `$.cjax` function just like what you would usually do with the `$ajax` function. + +```javascript +// .cjax (defined in /script/utils.js) is used to make POST request with CSRF token support +// alternatively you can use $.ajax with CSRF token in headers +// the header is named "X-CSRF-Token" and the value is taken from the head +// meta tag content (i.e. ) +$.cjax({ + url: './api/post', + type: 'POST', + data: { name: name, age: age, gender: gender }, + success: function(data) { + console.log('Response:', data); + $('#postResponseMessage').html(data).show(); + }, + error: function(xhr, status, error) { + console.error('Error:', error); + $('#postResponseMessage').text('An error occurred while processing your request.').show(); + } +}); +``` + +### POST Request with Vanilla JS + +It is possible to make POST request with Vanilla JS. Note that you will need to populate the csrf-token field yourself to make the request pass through the plugin UI request router in Zoraxy. Here is a basic example on how it could be done. + +```javascript +fetch('./api/post', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': csrfToken // Include the CSRF token in the headers + }, + body: JSON.stringify({{your_data_here}}) +}) +``` + +--- + +## 5. Full Code + +Here is the full code of the RESTFUL example for reference. + +Front-end (`plugins/restful-example/www/index.html`) + +```html + + + + + + + + + + + + + RESTful Example + + + + + + +
+
+
+

RESTFul API Example

+ +

Echo Test (HTTP GET)

+
+
+ + +
+ + +
+ + + +

Form Post Test (HTTP POST)

+
+
+ + +
+
+ + +
+
+ +
+ + +
+
+ + +
+
+ + +
+ + +
+
+ + +``` + + + +Backend (`plugins/restful-example/main.go`) + +```go +package main + +import ( + "embed" + _ "embed" + "encoding/json" + "fmt" + "net/http" + "strconv" + + plugin "example.com/zoraxy/restful-example/mod/zoraxy_plugin" +) + +const ( + PLUGIN_ID = "com.example.restful-example" + UI_PATH = "/" + WEB_ROOT = "/www" +) + +//go:embed www/* +var content embed.FS + +func main() { + // Serve the plugin intro spect + // This will print the plugin intro spect and exit if the -introspect flag is provided + runtimeCfg, err := plugin.ServeAndRecvSpec(&plugin.IntroSpect{ + ID: "com.example.restful-example", + Name: "Restful Example", + Author: "foobar", + AuthorContact: "admin@example.com", + Description: "A simple demo for making RESTful API calls in plugin", + URL: "https://example.com", + Type: plugin.PluginType_Utilities, + VersionMajor: 1, + VersionMinor: 0, + VersionPatch: 0, + + // As this is a utility plugin, we don't need to capture any traffic + // but only serve the UI, so we set the UI (relative to the plugin path) to "/" + UIPath: UI_PATH, + }) + if err != nil { + //Terminate or enter standalone mode here + panic(err) + } + + // Create a new PluginEmbedUIRouter that will serve the UI from web folder + // The router will also help to handle the termination of the plugin when + // a user wants to stop the plugin via Zoraxy Web UI + embedWebRouter := plugin.NewPluginEmbedUIRouter(PLUGIN_ID, &content, WEB_ROOT, UI_PATH) + embedWebRouter.RegisterTerminateHandler(func() { + // Do cleanup here if needed + fmt.Println("Restful-example Exited") + }, nil) + + //Register a simple API endpoint that will echo the request body + // Since we are using the default http.ServeMux, we can register the handler directly with the last + // parameter as nil + embedWebRouter.HandleFunc("/api/echo", func(w http.ResponseWriter, r *http.Request) { + // This is a simple echo API that will return the request body as response + name := r.URL.Query().Get("name") + if name == "" { + http.Error(w, "Missing 'name' query parameter", http.StatusBadRequest) + return + } + w.Header().Set("Content-Type", "application/json") + response := map[string]string{"message": fmt.Sprintf("Hello %s", name)} + if err := json.NewEncoder(w).Encode(response); err != nil { + http.Error(w, "Failed to encode response", http.StatusInternalServerError) + } + }, nil) + + // Here is another example of a POST API endpoint that will echo the form data + // This will handle POST requests to /api/post and return the form data as response + embedWebRouter.HandleFunc("/api/post", func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + if err := r.ParseForm(); err != nil { + http.Error(w, "Failed to parse form data", http.StatusBadRequest) + return + } + + for key, values := range r.PostForm { + for _, value := range values { + // Generate a simple HTML response + w.Header().Set("Content-Type", "text/html") + fmt.Fprintf(w, "%s: %s
", key, value) + } + } + }, nil) + + // Serve the restful-example page in the www folder + http.Handle(UI_PATH, embedWebRouter.Handler()) + fmt.Println("Restful-example started at http://127.0.0.1:" + strconv.Itoa(runtimeCfg.Port)) + err = http.ListenAndServe("127.0.0.1:"+strconv.Itoa(runtimeCfg.Port), nil) + if err != nil { + panic(err) + } + +} + +``` + + + +What you should expect to see if everything is correctly loaded and working in Zoray + +![image-20250530153148506](img/2. RESTful Example/image-20250530153148506.png) diff --git a/docs/plugins/docs/3. Basic Examples/img/1. Hello World/image-20250530134148399.png b/docs/plugins/docs/3. Basic Examples/img/1. Hello World/image-20250530134148399.png new file mode 100644 index 0000000000000000000000000000000000000000..4639a4591c94f973da7d287d83d481f7b9e384a8 GIT binary patch literal 37466 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 Y)N~#}TcN{@q{l1Cy_79^X7usD0W$2Pk^lez literal 0 HcmV?d00001 diff --git a/docs/plugins/docs/3. Basic Examples/img/2. RESTful Example/image-20250530153148506.png b/docs/plugins/docs/3. Basic Examples/img/2. RESTful Example/image-20250530153148506.png new file mode 100644 index 0000000000000000000000000000000000000000..37bddf39e82183b70eb5db0bb5eef9df88369bb2 GIT binary patch literal 58979 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 VUVadT3+BAX>&6yFRaac1{tLn!CdB{% literal 0 HcmV?d00001 diff --git a/docs/plugins/docs/index.md b/docs/plugins/docs/index.md index 86676ce..76d0d14 100644 --- a/docs/plugins/docs/index.md +++ b/docs/plugins/docs/index.md @@ -1,3 +1,7 @@ +
+ Zoraxy Plugin Banner +
+ # Index Welcome to the Zoraxy Plugin Documentation! @@ -14,4 +18,10 @@ No. Plugins operate in a separate process from Zoraxy. If a plugin crashes, Zora Yes, the plugin library and interface design are open source under the LGPL license. You are not required to disclose the source code of your plugin as long as you do not modify the plugin library and use it as-is. For more details on how to comply with the license, refer to the licensing documentation. ### How can I add my plugin to the official plugin store? -To add your plugin to the official plugin store, open a pull request (PR) in the plugin repository. \ No newline at end of file +To add your plugin to the official plugin store, open a pull request (PR) in the plugin repository. + +## GNU Free Documentation License + +This documentation is licensed under the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You may copy, distribute, and modify this document under the terms of the license. + +A copy of the license is available at [https://www.gnu.org/licenses/fdl-1.3.html](https://www.gnu.org/licenses/fdl-1.3.html). \ No newline at end of file diff --git a/docs/plugins/html/1. Introduction/1. What is Zoraxy Plugin.html b/docs/plugins/html/1. Introduction/1. What is Zoraxy Plugin.html index 86ea8ef..0b289b6 100644 --- a/docs/plugins/html/1. Introduction/1. What is Zoraxy Plugin.html +++ b/docs/plugins/html/1. Introduction/1. What is Zoraxy Plugin.html @@ -131,6 +131,9 @@
Hello World + + RESTful Example + index diff --git a/docs/plugins/html/1. Introduction/2. Getting Started.html b/docs/plugins/html/1. Introduction/2. Getting Started.html index 3721d96..db68971 100644 --- a/docs/plugins/html/1. Introduction/2. Getting Started.html +++ b/docs/plugins/html/1. Introduction/2. Getting Started.html @@ -131,6 +131,9 @@ Hello World + + RESTful Example + index diff --git a/docs/plugins/html/1. Introduction/3. Installing Plugin.html b/docs/plugins/html/1. Introduction/3. Installing Plugin.html index 90828c9..6417229 100644 --- a/docs/plugins/html/1. Introduction/3. Installing Plugin.html +++ b/docs/plugins/html/1. Introduction/3. Installing Plugin.html @@ -131,6 +131,9 @@ Hello World + + RESTful Example + index diff --git a/docs/plugins/html/1. Introduction/4. Enable Plugins.html b/docs/plugins/html/1. Introduction/4. Enable Plugins.html index e4e4613..b98cd21 100644 --- a/docs/plugins/html/1. Introduction/4. Enable Plugins.html +++ b/docs/plugins/html/1. Introduction/4. Enable Plugins.html @@ -131,6 +131,9 @@ Hello World + + RESTful Example + index diff --git a/docs/plugins/html/2. Architecture/1. Plugin Architecture.html b/docs/plugins/html/2. Architecture/1. Plugin Architecture.html index 2cd3baa..347aa64 100644 --- a/docs/plugins/html/2. Architecture/1. Plugin Architecture.html +++ b/docs/plugins/html/2. Architecture/1. Plugin Architecture.html @@ -131,6 +131,9 @@ Hello World + + RESTful Example + index diff --git a/docs/plugins/html/2. Architecture/2. Introspect.html b/docs/plugins/html/2. Architecture/2. Introspect.html index 5c92c2a..be1e09b 100644 --- a/docs/plugins/html/2. Architecture/2. Introspect.html +++ b/docs/plugins/html/2. Architecture/2. Introspect.html @@ -131,6 +131,9 @@ Hello World + + RESTful Example + index diff --git a/docs/plugins/html/2. Architecture/3. Configure.html b/docs/plugins/html/2. Architecture/3. Configure.html index 189a066..4de0002 100644 --- a/docs/plugins/html/2. Architecture/3. Configure.html +++ b/docs/plugins/html/2. Architecture/3. Configure.html @@ -131,6 +131,9 @@ Hello World + + RESTful Example + index diff --git a/docs/plugins/html/2. Architecture/4. Capture Modes.html b/docs/plugins/html/2. Architecture/4. Capture Modes.html index c826fdf..cb0e36d 100644 --- a/docs/plugins/html/2. Architecture/4. Capture Modes.html +++ b/docs/plugins/html/2. Architecture/4. Capture Modes.html @@ -131,6 +131,9 @@ Hello World + + RESTful Example + index diff --git a/docs/plugins/html/2. Architecture/5. Plugin UI.html b/docs/plugins/html/2. Architecture/5. Plugin UI.html index 1164e87..473221a 100644 --- a/docs/plugins/html/2. Architecture/5. Plugin UI.html +++ b/docs/plugins/html/2. Architecture/5. Plugin UI.html @@ -131,6 +131,9 @@ Hello World + + RESTful Example + index @@ -158,7 +161,7 @@

- It is generally recommended that a plugin have such UI exposed for easy configurations. + A plugin must provide a UI, as it is part of the control mechanism of the plugin life cycle. (i.e. Zoraxy use the plugin UI HTTP server to communicate with the plugin for control signals) As plugin installed via plugin store provides limited ways for a user to configure the plugin, the plugin web UI will be the best way for user to setup your plugin.

diff --git a/docs/plugins/html/3. Basic Examples/1. Hello World.html b/docs/plugins/html/3. Basic Examples/1. Hello World.html index d880c31..8cad55d 100644 --- a/docs/plugins/html/3. Basic Examples/1. Hello World.html +++ b/docs/plugins/html/3. Basic Examples/1. Hello World.html @@ -131,6 +131,9 @@
Hello World + + RESTful Example + index @@ -526,6 +529,11 @@ if err != nil { After you are done, restart Zoraxy and enable your plugin in the Plugin List. Now you can test and debug your plugin with your HTTP Proxy Rules. All the STDOUT and STDERR of your plugin will be forwarded to the STDOUT of Zoraxy as well as the log file.

+

+

+ image-20250530134148399 +
+

diff --git a/docs/plugins/html/3. Basic Examples/2. RESTful Example.html b/docs/plugins/html/3. Basic Examples/2. RESTful Example.html new file mode 100644 index 0000000..a74c330 --- /dev/null +++ b/docs/plugins/html/3. Basic Examples/2. RESTful Example.html @@ -0,0 +1,787 @@ + + + + + + + + RESTful Example | Zoraxy Documentation + + + + + + + + + + + + + + + + + + + + + + + + + +

+
+
+
+
+ +
+
+
+

+ RESTful API Call in Web UI +

+

+

+ Last Update: 29/05/2025 +

+

+
+

+

+ When developing a UI for your plugin, sometime you might need to make RESTFUL API calls to your plugin backend for setting up something or getting latest information from your plugin. In this example, I will show you how to create a plugin with RESTful api call capabilities with the embedded web server and the custom + + cjax + + function. +

+

+

+

+ + Notes: This example assumes you have basic understanding on how to use jQuery + + ajax + + request. + +

+

+

+

+ Lets get started! +

+

+
+

+ 1. Create the plugin folder structures +

+

+

+ This step is identical to the Hello World example, where you create a plugin folder with the required go project structure in the folder. Please refer to the Hello World example section 1 to 5 for details. +

+

+
+

+ 2. Create Introspect +

+

+

+ This is quite similar to the Hello World example as well, but we are changing some of the IDs to match what we want to do in this plugin. +

+

+
runtimeCfg, err := plugin.ServeAndRecvSpec(&plugin.IntroSpect{
+		ID:            "com.example.restful-example",
+		Name:          "Restful Example",
+		Author:        "foobar",
+		AuthorContact: "admin@example.com",
+		Description:   "A simple demo for making RESTful API calls in plugin",
+		URL:           "https://example.com",
+		Type:          plugin.PluginType_Utilities,
+		VersionMajor:  1,
+		VersionMinor:  0,
+		VersionPatch:  0,
+
+		// As this is a utility plugin, we don't need to capture any traffic
+		// but only serve the UI, so we set the UI (relative to the plugin path) to "/"
+		UIPath: UI_PATH,
+	})
+	if err != nil {
+		//Terminate or enter standalone mode here
+		panic(err)
+	}
+
+
+

+ 3. Create an embedded web server with handlers +

+

+

+ In this step, we create a basic embedded web file handler similar to the Hello World example, however, we will need to add a + + http.HandleFunc + + to the plugin so our front-end can request and communicate with the backend. +

+

+
embedWebRouter := plugin.NewPluginEmbedUIRouter(PLUGIN_ID, &content, WEB_ROOT, UI_PATH)
+embedWebRouter.RegisterTerminateHandler(func() {
+    fmt.Println("Restful-example Exited")
+}, nil)
+
+//Register a simple API endpoint that will echo the request body
+// Since we are using the default http.ServeMux, we can register the handler directly with the last
+// parameter as nil
+embedWebRouter.HandleFunc("/api/echo", func(w http.ResponseWriter, r *http.Request) {
+    //Some handler code here
+}, nil)
+
+

+

+ The + + embedWebRouter.HandleFunc + + last parameter is the + + http.Mux + + , where if you have multiple web server listening interface, you can fill in different Mux based on your implementation. On of the examples is that, when you are developing a static web server plugin, where you need a dedicated HTTP listening endpoint that is not the one Zoraxy assigned to your plugin, you need to create two http.Mux and assign one of them for Zoraxy plugin UI purpose. +

+

+
+

+ 4. Modify the front-end HTML file to make request to backend +

+

+

+ To make a RESTFUL API to your plugin, + + you must use relative path in your request URL + + . +

+

+

+

+ Absolute path that start with + + / + + is only use for accessing Zoraxy resouces. For example, when you access + + /img/logo.svg + + , Zoraxy webmin HTTP router will return the logo of Zoraxy for you instead of + + /plugins/your_plugin_name/{your_web_root}/img/logo.svg + + . +

+

+

+ Making GET request +

+

+ Making GET request is similar to what you would do in ordinary web development, but only limited to relative paths like + + ./api/foo/bar + + instead. Here is an example on a front-end and back-end implementation of a simple “echo” API. +

+

+

+ The API logic is simple: when you make a GET request to the API with + + ?name=foobar + + , it returns + + Hello foobar + + . Here is the backend implementation in your plugin code. +

+

+
embedWebRouter.HandleFunc("/api/echo", func(w http.ResponseWriter, r *http.Request) {
+		// This is a simple echo API that will return the request body as response
+		name := r.URL.Query().Get("name")
+		if name == "" {
+			http.Error(w, "Missing 'name' query parameter", http.StatusBadRequest)
+			return
+		}
+		w.Header().Set("Content-Type", "application/json")
+		response := map[string]string{"message": fmt.Sprintf("Hello %s", name)}
+		if err := json.NewEncoder(w).Encode(response); err != nil {
+			http.Error(w, "Failed to encode response", http.StatusInternalServerError)
+		}
+	}, nil)
+
+

+

+ And here is the front-end code in your HTML file +

+

+
<!-- The example below show how HTTP GET is used with Zoraxy plugin -->
+<h3>Echo Test (HTTP GET)</h3>
+<div class="ui form">
+    <div class="field">
+        <label for="nameInput">Enter your name:</label>
+        <input type="text" id="nameInput" placeholder="Your name">
+    </div>
+    <button class="ui button primary" id="sendRequestButton">Send Request</button>
+    <div class="ui message" id="responseMessage" style="display: none;"></div>
+</div>
+
+<script>
+    document.getElementById('sendRequestButton').addEventListener('click', function() {
+        const name = document.getElementById('nameInput').value;
+        if (name.trim() === "") {
+            alert("Please enter a name.");
+            return;
+        }
+        // Note the relative path is used here!
+        // GET do not require CSRF token, so you can use $.ajax directly
+        // or $.cjax (defined in /script/utils.js) to make GET request
+        $.ajax({
+            url: `./api/echo`,
+            type: 'GET',
+            data: { name: name },
+            success: function(data) {
+                console.log('Response:', data.message);
+                $('#responseMessage').text(data.message).show();
+            },
+            error: function(xhr, status, error) {
+                console.error('Error:', error);
+                $('#responseMessage').text('An error occurred while processing your request.').show();
+            }
+        });
+    });
+</script>
+
+

+ Making POST request +

+

+

+ Making POST request is also similar to GET request, except when making the request, you will need pass the CSRF-Token with the payload. This is required due to security reasons (See + + #267 + + for more details). +

+

+

+

+ Since the CSRF validation is done by Zoraxy, your plugin backend code can be implemented just like an ordinary handler. Here is an example POST handling function that receive a FORM POST and print it in an HTML response. +

+

+
embedWebRouter.HandleFunc("/api/post", func(w http.ResponseWriter, r *http.Request) {
+    if r.Method != http.MethodPost {
+        http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
+        return
+    }
+
+    if err := r.ParseForm(); err != nil {
+        http.Error(w, "Failed to parse form data", http.StatusBadRequest)
+        return
+    }
+
+    for key, values := range r.PostForm {
+        for _, value := range values {
+            // Generate a simple HTML response
+            w.Header().Set("Content-Type", "text/html")
+            fmt.Fprintf(w, "%s: %s<br>", key, value)
+        }
+    }
+}, nil)
+	
+
+

+

+ For the front-end, you will need to use the + + $.cjax + + function implemented in Zoraxy + + utils.js + + file. You can include this file by adding these two lines to your HTML file. +

+

+
<script src="/script/jquery-3.6.0.min.js"></script>
+<script src="/script/utils.js"></script>
+<!- More lines here -->
+<!-- The example below shows how form post can be used in plugin -->
+<h3>Form Post Test (HTTP POST)</h3>
+<div class="ui form">
+    <div class="field">
+        <label for="postNameInput">Name:</label>
+        <input type="text" id="postNameInput" placeholder="Your name">
+    </div>
+    <div class="field">
+        <label for="postAgeInput">Age:</label>
+        <input type="number" id="postAgeInput" placeholder="Your age">
+    </div>
+    <div class="field">
+        <label>Gender:</label>
+        <div class="ui checkbox">
+            <input type="checkbox" id="genderMale" name="gender" value="Male">
+            <label for="genderMale">Male</label>
+        </div>
+        <div class="ui checkbox">
+            <input type="checkbox" id="genderFemale" name="gender" value="Female">
+            <label for="genderFemale">Female</label>
+        </div>
+    </div>
+    <button class="ui button primary" id="postRequestButton">Send</button>
+    <div class="ui message" id="postResponseMessage" style="display: none;"></div>
+</div>
+
+

+

+ After that, you can call to the + + $.cjax + + function just like what you would usually do with the + + $ajax + + function. +

+

+
// .cjax (defined in /script/utils.js) is used to make POST request with CSRF token support
+// alternatively you can use $.ajax with CSRF token in headers
+// the header is named "X-CSRF-Token" and the value is taken from the head
+// meta tag content (i.e. <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">)
+$.cjax({
+    url: './api/post',
+    type: 'POST',
+    data: { name: name, age: age, gender: gender },
+    success: function(data) {
+    console.log('Response:', data);
+    	$('#postResponseMessage').html(data).show();
+    },
+    error: function(xhr, status, error) {
+        console.error('Error:', error);
+        $('#postResponseMessage').text('An error occurred while processing your request.').show();
+    }
+});
+
+

+ POST Request with Vanilla JS +

+

+

+ It is possible to make POST request with Vanilla JS. Note that you will need to populate the csrf-token field yourself to make the request pass through the plugin UI request router in Zoraxy. Here is a basic example on how it could be done. +

+

+
fetch('./api/post', {
+    method: 'POST',
+    headers: {
+        'Content-Type': 'application/json',
+        'X-CSRF-Token': csrfToken // Include the CSRF token in the headers
+    },
+    body: JSON.stringify({{your_data_here}})
+})
+
+
+

+ 5. Full Code +

+

+

+ Here is the full code of the RESTFUL example for reference. +

+

+

+

+ Front-end ( + + plugins/restful-example/www/index.html + + ) +

+

+
<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <!-- CSRF token, if your plugin need to make POST request to backend -->
+    <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
+    <link rel="stylesheet" href="/script/semantic/semantic.min.css">
+    <script src="/script/jquery-3.6.0.min.js"></script>
+    <script src="/script/semantic/semantic.min.js"></script>
+    <script src="/script/utils.js"></script>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <link rel="stylesheet" href="/main.css">
+    <title>RESTful Example</title>
+    <style>
+        body {
+            background-color: var(--theme_bg_primary);
+        }
+    </style>
+</head>
+<body>
+    <!-- Dark theme script must be included after body tag-->
+    <link rel="stylesheet" href="/darktheme.css">
+    <script src="/script/darktheme.js"></script>
+    <br>
+    <div class="standardContainer">
+        <div class="ui container">
+            <h1>RESTFul API Example</h1>
+            <!-- The example below show how HTTP GET is used with Zoraxy plugin -->
+            <h3>Echo Test (HTTP GET)</h3>
+            <div class="ui form">
+                <div class="field">
+                    <label for="nameInput">Enter your name:</label>
+                    <input type="text" id="nameInput" placeholder="Your name">
+                </div>
+                <button class="ui button primary" id="sendRequestButton">Send Request</button>
+                <div class="ui message" id="responseMessage" style="display: none;"></div>
+            </div>
+
+            <script>
+                document.getElementById('sendRequestButton').addEventListener('click', function() {
+                    const name = document.getElementById('nameInput').value;
+                    if (name.trim() === "") {
+                        alert("Please enter a name.");
+                        return;
+                    }
+                    // Note the relative path is used here!
+                    // GET do not require CSRF token, so you can use $.ajax directly
+                    // or $.cjax (defined in /script/utils.js) to make GET request
+                    $.ajax({
+                        url: `./api/echo`,
+                        type: 'GET',
+                        data: { name: name },
+                        success: function(data) {
+                            console.log('Response:', data.message);
+                            $('#responseMessage').text(data.message).show();
+                        },
+                        error: function(xhr, status, error) {
+                            console.error('Error:', error);
+                            $('#responseMessage').text('An error occurred while processing your request.').show();
+                        }
+                    });
+                });
+            </script>
+            <!-- The example below shows how form post can be used in plugin -->
+            <h3>Form Post Test (HTTP POST)</h3>
+            <div class="ui form">
+                <div class="field">
+                    <label for="postNameInput">Name:</label>
+                    <input type="text" id="postNameInput" placeholder="Your name">
+                </div>
+                <div class="field">
+                    <label for="postAgeInput">Age:</label>
+                    <input type="number" id="postAgeInput" placeholder="Your age">
+                </div>
+                <div class="field">
+                    <label>Gender:</label>
+                    <div class="ui checkbox">
+                        <input type="checkbox" id="genderMale" name="gender" value="Male">
+                        <label for="genderMale">Male</label>
+                    </div>
+                    <div class="ui checkbox">
+                        <input type="checkbox" id="genderFemale" name="gender" value="Female">
+                        <label for="genderFemale">Female</label>
+                    </div>
+                </div>
+                <button class="ui button primary" id="postRequestButton">Send</button>
+                <div class="ui message" id="postResponseMessage" style="display: none;"></div>
+            </div>
+
+            <script>
+                document.getElementById('postRequestButton').addEventListener('click', function() {
+                    const name = document.getElementById('postNameInput').value;
+                    const age = document.getElementById('postAgeInput').value;
+                    const genderMale = document.getElementById('genderMale').checked;
+                    const genderFemale = document.getElementById('genderFemale').checked;
+
+                    if (name.trim() === "" || age.trim() === "" || (!genderMale && !genderFemale)) {
+                        alert("Please fill out all fields.");
+                        return;
+                    }
+
+                    const gender = genderMale ? "Male" : "Female";
+                    
+                    // .cjax (defined in /script/utils.js) is used to make POST request with CSRF token support
+                    // alternatively you can use $.ajax with CSRF token in headers
+                    // the header is named "X-CSRF-Token" and the value is taken from the head
+                    // meta tag content (i.e. <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">)
+                    $.cjax({
+                        url: './api/post',
+                        type: 'POST',
+                        data: { name: name, age: age, gender: gender },
+                        success: function(data) {
+                            console.log('Response:', data);
+                            $('#postResponseMessage').html(data).show();
+                        },
+                        error: function(xhr, status, error) {
+                            console.error('Error:', error);
+                            $('#postResponseMessage').text('An error occurred while processing your request.').show();
+                        }
+                    });
+                });
+            </script>
+        </div>
+    </div>
+</body>
+</html>
+
+

+

+ Backend ( + + plugins/restful-example/main.go + + ) +

+

+
package main
+
+import (
+	"embed"
+	_ "embed"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"strconv"
+
+	plugin "example.com/zoraxy/restful-example/mod/zoraxy_plugin"
+)
+
+const (
+	PLUGIN_ID = "com.example.restful-example"
+	UI_PATH   = "/"
+	WEB_ROOT  = "/www"
+)
+
+//go:embed www/*
+var content embed.FS
+
+func main() {
+	// Serve the plugin intro spect
+	// This will print the plugin intro spect and exit if the -introspect flag is provided
+	runtimeCfg, err := plugin.ServeAndRecvSpec(&plugin.IntroSpect{
+		ID:            "com.example.restful-example",
+		Name:          "Restful Example",
+		Author:        "foobar",
+		AuthorContact: "admin@example.com",
+		Description:   "A simple demo for making RESTful API calls in plugin",
+		URL:           "https://example.com",
+		Type:          plugin.PluginType_Utilities,
+		VersionMajor:  1,
+		VersionMinor:  0,
+		VersionPatch:  0,
+
+		// As this is a utility plugin, we don't need to capture any traffic
+		// but only serve the UI, so we set the UI (relative to the plugin path) to "/"
+		UIPath: UI_PATH,
+	})
+	if err != nil {
+		//Terminate or enter standalone mode here
+		panic(err)
+	}
+
+	// Create a new PluginEmbedUIRouter that will serve the UI from web folder
+	// The router will also help to handle the termination of the plugin when
+	// a user wants to stop the plugin via Zoraxy Web UI
+	embedWebRouter := plugin.NewPluginEmbedUIRouter(PLUGIN_ID, &content, WEB_ROOT, UI_PATH)
+	embedWebRouter.RegisterTerminateHandler(func() {
+		// Do cleanup here if needed
+		fmt.Println("Restful-example Exited")
+	}, nil)
+
+	//Register a simple API endpoint that will echo the request body
+	// Since we are using the default http.ServeMux, we can register the handler directly with the last
+	// parameter as nil
+	embedWebRouter.HandleFunc("/api/echo", func(w http.ResponseWriter, r *http.Request) {
+		// This is a simple echo API that will return the request body as response
+		name := r.URL.Query().Get("name")
+		if name == "" {
+			http.Error(w, "Missing 'name' query parameter", http.StatusBadRequest)
+			return
+		}
+		w.Header().Set("Content-Type", "application/json")
+		response := map[string]string{"message": fmt.Sprintf("Hello %s", name)}
+		if err := json.NewEncoder(w).Encode(response); err != nil {
+			http.Error(w, "Failed to encode response", http.StatusInternalServerError)
+		}
+	}, nil)
+
+	// Here is another example of a POST API endpoint that will echo the form data
+	// This will handle POST requests to /api/post and return the form data as response
+	embedWebRouter.HandleFunc("/api/post", func(w http.ResponseWriter, r *http.Request) {
+		if r.Method != http.MethodPost {
+			http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
+			return
+		}
+
+		if err := r.ParseForm(); err != nil {
+			http.Error(w, "Failed to parse form data", http.StatusBadRequest)
+			return
+		}
+
+		for key, values := range r.PostForm {
+			for _, value := range values {
+				// Generate a simple HTML response
+				w.Header().Set("Content-Type", "text/html")
+				fmt.Fprintf(w, "%s: %s<br>", key, value)
+			}
+		}
+	}, nil)
+
+	// Serve the restful-example page in the www folder
+	http.Handle(UI_PATH, embedWebRouter.Handler())
+	fmt.Println("Restful-example started at http://127.0.0.1:" + strconv.Itoa(runtimeCfg.Port))
+	err = http.ListenAndServe("127.0.0.1:"+strconv.Itoa(runtimeCfg.Port), nil)
+	if err != nil {
+		panic(err)
+	}
+
+}
+
+
+

+

+ What you should expect to see if everything is correctly loaded and working in Zoray +

+

+

+

+ image-20250530153148506 +
+

+
+
+
+
+
+
+
+
+
+
+
+
+ Zoraxy © tobychui + + 2025 + +
+
+
+ + + \ No newline at end of file diff --git a/docs/plugins/html/3. Basic Examples/img/1. Hello World/image-20250530134148399.png b/docs/plugins/html/3. Basic Examples/img/1. Hello World/image-20250530134148399.png new file mode 100644 index 0000000000000000000000000000000000000000..4639a4591c94f973da7d287d83d481f7b9e384a8 GIT binary patch literal 37466 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 Y)N~#}TcN{@q{l1Cy_79^X7usD0W$2Pk^lez literal 0 HcmV?d00001 diff --git a/docs/plugins/html/3. Basic Examples/img/2. RESTful Example/image-20250530153148506.png b/docs/plugins/html/3. Basic Examples/img/2. RESTful Example/image-20250530153148506.png new file mode 100644 index 0000000000000000000000000000000000000000..37bddf39e82183b70eb5db0bb5eef9df88369bb2 GIT binary patch literal 58979 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 VUVadT3+BAX>&6yFRaac1{tLn!CdB{% literal 0 HcmV?d00001 diff --git a/docs/plugins/html/index.html b/docs/plugins/html/index.html index d040620..f3acdb2 100644 --- a/docs/plugins/html/index.html +++ b/docs/plugins/html/index.html @@ -131,6 +131,9 @@ Hello World + + RESTful Example + index @@ -141,6 +144,9 @@


diff --git a/docs/plugins/index.html b/docs/plugins/index.html index 08bc4ae..e41980f 100644 --- a/docs/plugins/index.html +++ b/docs/plugins/index.html @@ -3,7 +3,7 @@ - + Redirecting... diff --git a/docs/plugins/index.json b/docs/plugins/index.json index 3bf1d86..52cc9e7 100644 --- a/docs/plugins/index.json +++ b/docs/plugins/index.json @@ -71,6 +71,11 @@ "filename": "3. Basic Examples/1. Hello World.md", "title": "Hello World", "type": "file" + }, + { + "filename": "3. Basic Examples/2. RESTful Example.md", + "title": "RESTful Example", + "type": "file" } ] }, diff --git a/docs/plugins/main.go b/docs/plugins/main.go index 10a21b8..05f6f13 100644 --- a/docs/plugins/main.go +++ b/docs/plugins/main.go @@ -41,8 +41,8 @@ func main() { func startWebServerInBackground() { go func() { - server := &http.Server{Addr: ":8080", Handler: http.DefaultServeMux} http.DefaultServeMux = http.NewServeMux() + server := &http.Server{Addr: ":8080", Handler: http.DefaultServeMux} http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.FileServer(http.Dir("./")).ServeHTTP(w, r) }) diff --git a/example/plugins/restful-example/go.mod b/example/plugins/restful-example/go.mod new file mode 100644 index 0000000..6ec4470 --- /dev/null +++ b/example/plugins/restful-example/go.mod @@ -0,0 +1,3 @@ +module example.com/zoraxy/restful-example + +go 1.23.6 diff --git a/example/plugins/restful-example/icon.png b/example/plugins/restful-example/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..69c3e2984c2b0a95bbd0f9102f590a43edd4de05 GIT binary patch literal 14120 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", key, value) + } + } + }, nil) + + // Serve the restful-example page in the www folder + http.Handle(UI_PATH, embedWebRouter.Handler()) + fmt.Println("Restful-example started at http://127.0.0.1:" + strconv.Itoa(runtimeCfg.Port)) + err = http.ListenAndServe("127.0.0.1:"+strconv.Itoa(runtimeCfg.Port), nil) + if err != nil { + panic(err) + } + +} diff --git a/example/plugins/restful-example/mod/zoraxy_plugin/README.txt b/example/plugins/restful-example/mod/zoraxy_plugin/README.txt new file mode 100644 index 0000000..ed8a405 --- /dev/null +++ b/example/plugins/restful-example/mod/zoraxy_plugin/README.txt @@ -0,0 +1,19 @@ +# Zoraxy Plugin + +## Overview +This module serves as a template for building your own plugins for the Zoraxy Reverse Proxy. By copying this module to your plugin mod folder, you can create a new plugin with the necessary structure and components. + +## Instructions + +1. **Copy the Module:** + - Copy the entire `zoraxy_plugin` module to your plugin mod folder. + +2. **Include the Structure:** + - Ensure that you maintain the directory structure and file organization as provided in this module. + +3. **Modify as Needed:** + - Customize the copied module to implement the desired functionality for your plugin. + +## Directory Structure + zoraxy_plugin: Handle -introspect and -configuration process required for plugin loading and startup + embed_webserver: Handle embeded web server routing and injecting csrf token to your plugin served UI pages \ No newline at end of file diff --git a/example/plugins/restful-example/mod/zoraxy_plugin/dev_webserver.go b/example/plugins/restful-example/mod/zoraxy_plugin/dev_webserver.go new file mode 100644 index 0000000..9bed106 --- /dev/null +++ b/example/plugins/restful-example/mod/zoraxy_plugin/dev_webserver.go @@ -0,0 +1,145 @@ +package zoraxy_plugin + +import ( + "fmt" + "net/http" + "os" + "strings" + "time" +) + +type PluginUiDebugRouter struct { + PluginID string //The ID of the plugin + TargetDir string //The directory where the UI files are stored + HandlerPrefix string //The prefix of the handler used to route this router, e.g. /ui + EnableDebug bool //Enable debug mode + terminateHandler func() //The handler to be called when the plugin is terminated +} + +// NewPluginFileSystemUIRouter creates a new PluginUiRouter with file system +// The targetDir is the directory where the UI files are stored (e.g. ./www) +// The handlerPrefix is the prefix of the handler used to route this router +// The handlerPrefix should start with a slash (e.g. /ui) that matches the http.Handle path +// All prefix should not end with a slash +func NewPluginFileSystemUIRouter(pluginID string, targetDir string, handlerPrefix string) *PluginUiDebugRouter { + //Make sure all prefix are in /prefix format + if !strings.HasPrefix(handlerPrefix, "/") { + handlerPrefix = "/" + handlerPrefix + } + handlerPrefix = strings.TrimSuffix(handlerPrefix, "/") + + //Return the PluginUiRouter + return &PluginUiDebugRouter{ + PluginID: pluginID, + TargetDir: targetDir, + HandlerPrefix: handlerPrefix, + } +} + +func (p *PluginUiDebugRouter) populateCSRFToken(r *http.Request, fsHandler http.Handler) http.Handler { + //Get the CSRF token from header + csrfToken := r.Header.Get("X-Zoraxy-Csrf") + if csrfToken == "" { + csrfToken = "missing-csrf-token" + } + + //Return the middleware + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Check if the request is for an HTML file + if strings.HasSuffix(r.URL.Path, ".html") { + //Read the target file from file system + targetFilePath := strings.TrimPrefix(r.URL.Path, "/") + targetFilePath = p.TargetDir + "/" + targetFilePath + targetFilePath = strings.TrimPrefix(targetFilePath, "/") + targetFileContent, err := os.ReadFile(targetFilePath) + if err != nil { + http.Error(w, "File not found", http.StatusNotFound) + return + } + body := string(targetFileContent) + body = strings.ReplaceAll(body, "{{.csrfToken}}", csrfToken) + w.Header().Set("Content-Type", "text/html") + w.WriteHeader(http.StatusOK) + w.Write([]byte(body)) + return + } else if strings.HasSuffix(r.URL.Path, "/") { + //Check if the request is for a directory + //Check if the directory has an index.html file + targetFilePath := strings.TrimPrefix(r.URL.Path, "/") + targetFilePath = p.TargetDir + "/" + targetFilePath + "index.html" + targetFilePath = strings.TrimPrefix(targetFilePath, "/") + if _, err := os.Stat(targetFilePath); err == nil { + //Serve the index.html file + targetFileContent, err := os.ReadFile(targetFilePath) + if err != nil { + http.Error(w, "File not found", http.StatusNotFound) + return + } + body := string(targetFileContent) + body = strings.ReplaceAll(body, "{{.csrfToken}}", csrfToken) + w.Header().Set("Content-Type", "text/html") + w.WriteHeader(http.StatusOK) + w.Write([]byte(body)) + return + } + } + + //Call the next handler + fsHandler.ServeHTTP(w, r) + }) + +} + +// GetHttpHandler returns the http.Handler for the PluginUiRouter +func (p *PluginUiDebugRouter) Handler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + //Remove the plugin UI handler path prefix + if p.EnableDebug { + fmt.Print("Request URL:", r.URL.Path, " rewriting to ") + } + + rewrittenURL := r.RequestURI + rewrittenURL = strings.TrimPrefix(rewrittenURL, p.HandlerPrefix) + rewrittenURL = strings.ReplaceAll(rewrittenURL, "//", "/") + r.URL.Path = rewrittenURL + r.RequestURI = rewrittenURL + if p.EnableDebug { + fmt.Println(r.URL.Path) + } + + //Serve the file from the file system + fsHandler := http.FileServer(http.Dir(p.TargetDir)) + + // Replace {{csrf_token}} with the actual CSRF token and serve the file + p.populateCSRFToken(r, fsHandler).ServeHTTP(w, r) + }) +} + +// RegisterTerminateHandler registers the terminate handler for the PluginUiRouter +// The terminate handler will be called when the plugin is terminated from Zoraxy plugin manager +// if mux is nil, the handler will be registered to http.DefaultServeMux +func (p *PluginUiDebugRouter) RegisterTerminateHandler(termFunc func(), mux *http.ServeMux) { + p.terminateHandler = termFunc + if mux == nil { + mux = http.DefaultServeMux + } + mux.HandleFunc(p.HandlerPrefix+"/term", func(w http.ResponseWriter, r *http.Request) { + p.terminateHandler() + w.WriteHeader(http.StatusOK) + go func() { + //Make sure the response is sent before the plugin is terminated + time.Sleep(100 * time.Millisecond) + os.Exit(0) + }() + }) +} + +// Attach the file system UI handler to the target http.ServeMux +func (p *PluginUiDebugRouter) AttachHandlerToMux(mux *http.ServeMux) { + if mux == nil { + mux = http.DefaultServeMux + } + + p.HandlerPrefix = strings.TrimSuffix(p.HandlerPrefix, "/") + mux.Handle(p.HandlerPrefix+"/", p.Handler()) +} diff --git a/example/plugins/restful-example/mod/zoraxy_plugin/dynamic_router.go b/example/plugins/restful-example/mod/zoraxy_plugin/dynamic_router.go new file mode 100644 index 0000000..1dc53ce --- /dev/null +++ b/example/plugins/restful-example/mod/zoraxy_plugin/dynamic_router.go @@ -0,0 +1,162 @@ +package zoraxy_plugin + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strings" +) + +/* + + Dynamic Path Handler + +*/ + +type SniffResult int + +const ( + SniffResultAccpet SniffResult = iota // Forward the request to this plugin dynamic capture ingress + SniffResultSkip // Skip this plugin and let the next plugin handle the request +) + +type SniffHandler func(*DynamicSniffForwardRequest) SniffResult + +/* +RegisterDynamicSniffHandler registers a dynamic sniff handler for a path +You can decide to accept or skip the request based on the request header and paths +*/ +func (p *PathRouter) RegisterDynamicSniffHandler(sniff_ingress string, mux *http.ServeMux, handler SniffHandler) { + if !strings.HasSuffix(sniff_ingress, "/") { + sniff_ingress = sniff_ingress + "/" + } + mux.Handle(sniff_ingress, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if p.enableDebugPrint { + fmt.Println("Request captured by dynamic sniff path: " + r.RequestURI) + } + + // Decode the request payload + jsonBytes, err := io.ReadAll(r.Body) + if err != nil { + if p.enableDebugPrint { + fmt.Println("Error reading request body:", err) + } + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + payload, err := DecodeForwardRequestPayload(jsonBytes) + if err != nil { + if p.enableDebugPrint { + fmt.Println("Error decoding request payload:", err) + fmt.Print("Payload: ") + fmt.Println(string(jsonBytes)) + } + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + + // Get the forwarded request UUID + forwardUUID := r.Header.Get("X-Zoraxy-RequestID") + payload.requestUUID = forwardUUID + payload.rawRequest = r + + sniffResult := handler(&payload) + if sniffResult == SniffResultAccpet { + w.WriteHeader(http.StatusOK) + w.Write([]byte("OK")) + } else { + w.WriteHeader(http.StatusNotImplemented) + w.Write([]byte("SKIP")) + } + })) +} + +// RegisterDynamicCaptureHandle register the dynamic capture ingress path with a handler +func (p *PathRouter) RegisterDynamicCaptureHandle(capture_ingress string, mux *http.ServeMux, handlefunc func(http.ResponseWriter, *http.Request)) { + if !strings.HasSuffix(capture_ingress, "/") { + capture_ingress = capture_ingress + "/" + } + mux.Handle(capture_ingress, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if p.enableDebugPrint { + fmt.Println("Request captured by dynamic capture path: " + r.RequestURI) + } + + rewrittenURL := r.RequestURI + rewrittenURL = strings.TrimPrefix(rewrittenURL, capture_ingress) + rewrittenURL = strings.ReplaceAll(rewrittenURL, "//", "/") + if rewrittenURL == "" { + rewrittenURL = "/" + } + if !strings.HasPrefix(rewrittenURL, "/") { + rewrittenURL = "/" + rewrittenURL + } + r.RequestURI = rewrittenURL + + handlefunc(w, r) + })) +} + +/* + Sniffing and forwarding + + The following functions are here to help with + sniffing and forwarding requests to the dynamic + router. +*/ +// A custom request object to be used in the dynamic sniffing +type DynamicSniffForwardRequest struct { + Method string `json:"method"` + Hostname string `json:"hostname"` + URL string `json:"url"` + Header map[string][]string `json:"header"` + RemoteAddr string `json:"remote_addr"` + Host string `json:"host"` + RequestURI string `json:"request_uri"` + Proto string `json:"proto"` + ProtoMajor int `json:"proto_major"` + ProtoMinor int `json:"proto_minor"` + + /* Internal use */ + rawRequest *http.Request `json:"-"` + requestUUID string `json:"-"` +} + +// GetForwardRequestPayload returns a DynamicSniffForwardRequest object from an http.Request object +func EncodeForwardRequestPayload(r *http.Request) DynamicSniffForwardRequest { + return DynamicSniffForwardRequest{ + Method: r.Method, + Hostname: r.Host, + URL: r.URL.String(), + Header: r.Header, + RemoteAddr: r.RemoteAddr, + Host: r.Host, + RequestURI: r.RequestURI, + Proto: r.Proto, + ProtoMajor: r.ProtoMajor, + ProtoMinor: r.ProtoMinor, + rawRequest: r, + } +} + +// DecodeForwardRequestPayload decodes JSON bytes into a DynamicSniffForwardRequest object +func DecodeForwardRequestPayload(jsonBytes []byte) (DynamicSniffForwardRequest, error) { + var payload DynamicSniffForwardRequest + err := json.Unmarshal(jsonBytes, &payload) + if err != nil { + return DynamicSniffForwardRequest{}, err + } + return payload, nil +} + +// GetRequest returns the original http.Request object, for debugging purposes +func (dsfr *DynamicSniffForwardRequest) GetRequest() *http.Request { + return dsfr.rawRequest +} + +// GetRequestUUID returns the request UUID +// if this UUID is empty string, that might indicate the request +// is not coming from the dynamic router +func (dsfr *DynamicSniffForwardRequest) GetRequestUUID() string { + return dsfr.requestUUID +} diff --git a/example/plugins/restful-example/mod/zoraxy_plugin/embed_webserver.go b/example/plugins/restful-example/mod/zoraxy_plugin/embed_webserver.go new file mode 100644 index 0000000..b68b417 --- /dev/null +++ b/example/plugins/restful-example/mod/zoraxy_plugin/embed_webserver.go @@ -0,0 +1,174 @@ +package zoraxy_plugin + +import ( + "embed" + "fmt" + "io/fs" + "net/http" + "net/url" + "os" + "strings" + "time" +) + +type PluginUiRouter struct { + PluginID string //The ID of the plugin + TargetFs *embed.FS //The embed.FS where the UI files are stored + TargetFsPrefix string //The prefix of the embed.FS where the UI files are stored, e.g. /web + HandlerPrefix string //The prefix of the handler used to route this router, e.g. /ui + EnableDebug bool //Enable debug mode + terminateHandler func() //The handler to be called when the plugin is terminated +} + +// NewPluginEmbedUIRouter creates a new PluginUiRouter with embed.FS +// The targetFsPrefix is the prefix of the embed.FS where the UI files are stored +// The targetFsPrefix should be relative to the root of the embed.FS +// The targetFsPrefix should start with a slash (e.g. /web) that corresponds to the root folder of the embed.FS +// The handlerPrefix is the prefix of the handler used to route this router +// The handlerPrefix should start with a slash (e.g. /ui) that matches the http.Handle path +// All prefix should not end with a slash +func NewPluginEmbedUIRouter(pluginID string, targetFs *embed.FS, targetFsPrefix string, handlerPrefix string) *PluginUiRouter { + //Make sure all prefix are in /prefix format + if !strings.HasPrefix(targetFsPrefix, "/") { + targetFsPrefix = "/" + targetFsPrefix + } + targetFsPrefix = strings.TrimSuffix(targetFsPrefix, "/") + + if !strings.HasPrefix(handlerPrefix, "/") { + handlerPrefix = "/" + handlerPrefix + } + handlerPrefix = strings.TrimSuffix(handlerPrefix, "/") + + //Return the PluginUiRouter + return &PluginUiRouter{ + PluginID: pluginID, + TargetFs: targetFs, + TargetFsPrefix: targetFsPrefix, + HandlerPrefix: handlerPrefix, + } +} + +func (p *PluginUiRouter) populateCSRFToken(r *http.Request, fsHandler http.Handler) http.Handler { + //Get the CSRF token from header + csrfToken := r.Header.Get("X-Zoraxy-Csrf") + if csrfToken == "" { + csrfToken = "missing-csrf-token" + } + + //Return the middleware + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Check if the request is for an HTML file + if strings.HasSuffix(r.URL.Path, ".html") { + //Read the target file from embed.FS + targetFilePath := strings.TrimPrefix(r.URL.Path, "/") + targetFilePath = p.TargetFsPrefix + "/" + targetFilePath + targetFilePath = strings.TrimPrefix(targetFilePath, "/") + targetFileContent, err := fs.ReadFile(*p.TargetFs, targetFilePath) + if err != nil { + http.Error(w, "File not found", http.StatusNotFound) + return + } + body := string(targetFileContent) + body = strings.ReplaceAll(body, "{{.csrfToken}}", csrfToken) + w.Header().Set("Content-Type", "text/html") + w.WriteHeader(http.StatusOK) + w.Write([]byte(body)) + return + } else if strings.HasSuffix(r.URL.Path, "/") { + // Check if the directory has an index.html file + indexFilePath := strings.TrimPrefix(r.URL.Path, "/") + "index.html" + indexFilePath = p.TargetFsPrefix + "/" + indexFilePath + indexFilePath = strings.TrimPrefix(indexFilePath, "/") + indexFileContent, err := fs.ReadFile(*p.TargetFs, indexFilePath) + if err == nil { + body := string(indexFileContent) + body = strings.ReplaceAll(body, "{{.csrfToken}}", csrfToken) + w.Header().Set("Content-Type", "text/html") + w.WriteHeader(http.StatusOK) + w.Write([]byte(body)) + return + } + } + + //Call the next handler + fsHandler.ServeHTTP(w, r) + }) + +} + +// GetHttpHandler returns the http.Handler for the PluginUiRouter +func (p *PluginUiRouter) Handler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + //Remove the plugin UI handler path prefix + if p.EnableDebug { + fmt.Print("Request URL:", r.URL.Path, " rewriting to ") + } + + rewrittenURL := r.RequestURI + rewrittenURL = strings.TrimPrefix(rewrittenURL, p.HandlerPrefix) + rewrittenURL = strings.ReplaceAll(rewrittenURL, "//", "/") + r.URL, _ = url.Parse(rewrittenURL) + r.RequestURI = rewrittenURL + if p.EnableDebug { + fmt.Println(r.URL.Path) + } + + //Serve the file from the embed.FS + subFS, err := fs.Sub(*p.TargetFs, strings.TrimPrefix(p.TargetFsPrefix, "/")) + if err != nil { + fmt.Println(err.Error()) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + + // Replace {{csrf_token}} with the actual CSRF token and serve the file + p.populateCSRFToken(r, http.FileServer(http.FS(subFS))).ServeHTTP(w, r) + }) +} + +// RegisterTerminateHandler registers the terminate handler for the PluginUiRouter +// The terminate handler will be called when the plugin is terminated from Zoraxy plugin manager +// if mux is nil, the handler will be registered to http.DefaultServeMux +func (p *PluginUiRouter) RegisterTerminateHandler(termFunc func(), mux *http.ServeMux) { + p.terminateHandler = termFunc + if mux == nil { + mux = http.DefaultServeMux + } + mux.HandleFunc(p.HandlerPrefix+"/term", func(w http.ResponseWriter, r *http.Request) { + p.terminateHandler() + w.WriteHeader(http.StatusOK) + go func() { + //Make sure the response is sent before the plugin is terminated + time.Sleep(100 * time.Millisecond) + os.Exit(0) + }() + }) +} + +// HandleFunc registers a handler function for the given pattern +// The pattern should start with the handler prefix, e.g. /ui/hello +// If the pattern does not start with the handler prefix, it will be prepended with the handler prefix +func (p *PluginUiRouter) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request), mux *http.ServeMux) { + // If mux is nil, use the default ServeMux + if mux == nil { + mux = http.DefaultServeMux + } + + // Make sure the pattern starts with the handler prefix + if !strings.HasPrefix(pattern, p.HandlerPrefix) { + pattern = p.HandlerPrefix + pattern + } + + // Register the handler with the http.ServeMux + mux.HandleFunc(pattern, handler) +} + +// Attach the embed UI handler to the target http.ServeMux +func (p *PluginUiRouter) AttachHandlerToMux(mux *http.ServeMux) { + if mux == nil { + mux = http.DefaultServeMux + } + + p.HandlerPrefix = strings.TrimSuffix(p.HandlerPrefix, "/") + mux.Handle(p.HandlerPrefix+"/", p.Handler()) +} diff --git a/example/plugins/restful-example/mod/zoraxy_plugin/static_router.go b/example/plugins/restful-example/mod/zoraxy_plugin/static_router.go new file mode 100644 index 0000000..f4abcb7 --- /dev/null +++ b/example/plugins/restful-example/mod/zoraxy_plugin/static_router.go @@ -0,0 +1,105 @@ +package zoraxy_plugin + +import ( + "fmt" + "net/http" + "sort" + "strings" +) + +type PathRouter struct { + enableDebugPrint bool + pathHandlers map[string]http.Handler + defaultHandler http.Handler +} + +// NewPathRouter creates a new PathRouter +func NewPathRouter() *PathRouter { + return &PathRouter{ + enableDebugPrint: false, + pathHandlers: make(map[string]http.Handler), + } +} + +// RegisterPathHandler registers a handler for a path +func (p *PathRouter) RegisterPathHandler(path string, handler http.Handler) { + path = strings.TrimSuffix(path, "/") + p.pathHandlers[path] = handler +} + +// RemovePathHandler removes a handler for a path +func (p *PathRouter) RemovePathHandler(path string) { + delete(p.pathHandlers, path) +} + +// SetDefaultHandler sets the default handler for the router +// This handler will be called if no path handler is found +func (p *PathRouter) SetDefaultHandler(handler http.Handler) { + p.defaultHandler = handler +} + +// SetDebugPrintMode sets the debug print mode +func (p *PathRouter) SetDebugPrintMode(enable bool) { + p.enableDebugPrint = enable +} + +// StartStaticCapture starts the static capture ingress +func (p *PathRouter) RegisterStaticCaptureHandle(capture_ingress string, mux *http.ServeMux) { + if !strings.HasSuffix(capture_ingress, "/") { + capture_ingress = capture_ingress + "/" + } + mux.Handle(capture_ingress, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + p.staticCaptureServeHTTP(w, r) + })) +} + +// staticCaptureServeHTTP serves the static capture path using user defined handler +func (p *PathRouter) staticCaptureServeHTTP(w http.ResponseWriter, r *http.Request) { + capturePath := r.Header.Get("X-Zoraxy-Capture") + if capturePath != "" { + if p.enableDebugPrint { + fmt.Printf("Using capture path: %s\n", capturePath) + } + originalURI := r.Header.Get("X-Zoraxy-Uri") + r.URL.Path = originalURI + if handler, ok := p.pathHandlers[capturePath]; ok { + handler.ServeHTTP(w, r) + return + } + } + p.defaultHandler.ServeHTTP(w, r) +} + +func (p *PathRouter) PrintRequestDebugMessage(r *http.Request) { + if p.enableDebugPrint { + fmt.Printf("Capture Request with path: %s \n\n**Request Headers** \n\n", r.URL.Path) + keys := make([]string, 0, len(r.Header)) + for key := range r.Header { + keys = append(keys, key) + } + sort.Strings(keys) + for _, key := range keys { + for _, value := range r.Header[key] { + fmt.Printf("%s: %s\n", key, value) + } + } + + fmt.Printf("\n\n**Request Details**\n\n") + fmt.Printf("Method: %s\n", r.Method) + fmt.Printf("URL: %s\n", r.URL.String()) + fmt.Printf("Proto: %s\n", r.Proto) + fmt.Printf("Host: %s\n", r.Host) + fmt.Printf("RemoteAddr: %s\n", r.RemoteAddr) + fmt.Printf("RequestURI: %s\n", r.RequestURI) + fmt.Printf("ContentLength: %d\n", r.ContentLength) + fmt.Printf("TransferEncoding: %v\n", r.TransferEncoding) + fmt.Printf("Close: %v\n", r.Close) + fmt.Printf("Form: %v\n", r.Form) + fmt.Printf("PostForm: %v\n", r.PostForm) + fmt.Printf("MultipartForm: %v\n", r.MultipartForm) + fmt.Printf("Trailer: %v\n", r.Trailer) + fmt.Printf("RemoteAddr: %s\n", r.RemoteAddr) + fmt.Printf("RequestURI: %s\n", r.RequestURI) + + } +} diff --git a/example/plugins/restful-example/mod/zoraxy_plugin/zoraxy_plugin.go b/example/plugins/restful-example/mod/zoraxy_plugin/zoraxy_plugin.go new file mode 100644 index 0000000..737e928 --- /dev/null +++ b/example/plugins/restful-example/mod/zoraxy_plugin/zoraxy_plugin.go @@ -0,0 +1,176 @@ +package zoraxy_plugin + +import ( + "encoding/json" + "fmt" + "os" + "strings" +) + +/* + Plugins Includes.go + + This file is copied from Zoraxy source code + You can always find the latest version under mod/plugins/includes.go + Usually this file are backward compatible +*/ + +type PluginType int + +const ( + PluginType_Router PluginType = 0 //Router Plugin, used for handling / routing / forwarding traffic + PluginType_Utilities PluginType = 1 //Utilities Plugin, used for utilities like Zerotier or Static Web Server that do not require interception with the dpcore +) + +type StaticCaptureRule struct { + CapturePath string `json:"capture_path"` + //To be expanded +} + +type ControlStatusCode int + +const ( + ControlStatusCode_CAPTURED ControlStatusCode = 280 //Traffic captured by plugin, ask Zoraxy not to process the traffic + ControlStatusCode_UNHANDLED ControlStatusCode = 284 //Traffic not handled by plugin, ask Zoraxy to process the traffic + ControlStatusCode_ERROR ControlStatusCode = 580 //Error occurred while processing the traffic, ask Zoraxy to process the traffic and log the error +) + +type SubscriptionEvent struct { + EventName string `json:"event_name"` + EventSource string `json:"event_source"` + Payload string `json:"payload"` //Payload of the event, can be empty +} + +type RuntimeConstantValue struct { + ZoraxyVersion string `json:"zoraxy_version"` + ZoraxyUUID string `json:"zoraxy_uuid"` + DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not +} + +/* +IntroSpect Payload + +When the plugin is initialized with -introspect flag, +the plugin shell return this payload as JSON and exit +*/ +type IntroSpect struct { + /* Plugin metadata */ + ID string `json:"id"` //Unique ID of your plugin, recommended using your own domain in reverse like com.yourdomain.pluginname + Name string `json:"name"` //Name of your plugin + Author string `json:"author"` //Author name of your plugin + AuthorContact string `json:"author_contact"` //Author contact of your plugin, like email + Description string `json:"description"` //Description of your plugin + URL string `json:"url"` //URL of your plugin + Type PluginType `json:"type"` //Type of your plugin, Router(0) or Utilities(1) + VersionMajor int `json:"version_major"` //Major version of your plugin + VersionMinor int `json:"version_minor"` //Minor version of your plugin + VersionPatch int `json:"version_patch"` //Patch version of your plugin + + /* + + Endpoint Settings + + */ + + /* + Static Capture Settings + + Once plugin is enabled these rules always applies to the enabled HTTP Proxy rule + This is faster than dynamic capture, but less flexible + */ + StaticCapturePaths []StaticCaptureRule `json:"static_capture_paths"` //Static capture paths of your plugin, see Zoraxy documentation for more details + StaticCaptureIngress string `json:"static_capture_ingress"` //Static capture ingress path of your plugin (e.g. /s_handler) + + /* + Dynamic Capture Settings + + Once plugin is enabled, these rules will be captured and forward to plugin sniff + if the plugin sniff returns 280, the traffic will be captured + otherwise, the traffic will be forwarded to the next plugin + This is slower than static capture, but more flexible + */ + DynamicCaptureSniff string `json:"dynamic_capture_sniff"` //Dynamic capture sniff path of your plugin (e.g. /d_sniff) + DynamicCaptureIngress string `json:"dynamic_capture_ingress"` //Dynamic capture ingress path of your plugin (e.g. /d_handler) + + /* UI Path for your plugin */ + UIPath string `json:"ui_path"` //UI path of your plugin (e.g. /ui), will proxy the whole subpath tree to Zoraxy Web UI as plugin UI + + /* Subscriptions Settings */ + SubscriptionPath string `json:"subscription_path"` //Subscription event path of your plugin (e.g. /notifyme), a POST request with SubscriptionEvent as body will be sent to this path when the event is triggered + SubscriptionsEvents map[string]string `json:"subscriptions_events"` //Subscriptions events of your plugin, see Zoraxy documentation for more details +} + +/* +ServeIntroSpect Function + +This function will check if the plugin is initialized with -introspect flag, +if so, it will print the intro spect and exit + +Place this function at the beginning of your plugin main function +*/ +func ServeIntroSpect(pluginSpect *IntroSpect) { + if len(os.Args) > 1 && os.Args[1] == "-introspect" { + //Print the intro spect and exit + jsonData, _ := json.MarshalIndent(pluginSpect, "", " ") + fmt.Println(string(jsonData)) + os.Exit(0) + } +} + +/* +ConfigureSpec Payload + +Zoraxy will start your plugin with -configure flag, +the plugin shell read this payload as JSON and configure itself +by the supplied values like starting a web server at given port +that listens to 127.0.0.1:port +*/ +type ConfigureSpec struct { + Port int `json:"port"` //Port to listen + RuntimeConst RuntimeConstantValue `json:"runtime_const"` //Runtime constant values + //To be expanded +} + +/* +RecvExecuteConfigureSpec Function + +This function will read the configure spec from Zoraxy +and return the ConfigureSpec object + +Place this function after ServeIntroSpect function in your plugin main function +*/ +func RecvConfigureSpec() (*ConfigureSpec, error) { + for i, arg := range os.Args { + if strings.HasPrefix(arg, "-configure=") { + var configSpec ConfigureSpec + if err := json.Unmarshal([]byte(arg[11:]), &configSpec); err != nil { + return nil, err + } + return &configSpec, nil + } else if arg == "-configure" { + var configSpec ConfigureSpec + var nextArg string + if len(os.Args) > i+1 { + nextArg = os.Args[i+1] + if err := json.Unmarshal([]byte(nextArg), &configSpec); err != nil { + return nil, err + } + } else { + return nil, fmt.Errorf("No port specified after -configure flag") + } + return &configSpec, nil + } + } + return nil, fmt.Errorf("No -configure flag found") +} + +/* +ServeAndRecvSpec Function + +This function will serve the intro spect and return the configure spec +See the ServeIntroSpect and RecvConfigureSpec for more details +*/ +func ServeAndRecvSpec(pluginSpect *IntroSpect) (*ConfigureSpec, error) { + ServeIntroSpect(pluginSpect) + return RecvConfigureSpec() +} diff --git a/example/plugins/restful-example/www/index.html b/example/plugins/restful-example/www/index.html new file mode 100644 index 0000000..6f269a5 --- /dev/null +++ b/example/plugins/restful-example/www/index.html @@ -0,0 +1,126 @@ + + + + + + + + + + + + + RESTful Example + + + + + + +
+
+
+

RESTFul API Example

+ +

Echo Test (HTTP GET)

+
+
+ + +
+ + +
+ + + +

Form Post Test (HTTP POST)

+
+
+ + +
+
+ + +
+
+ +
+ + +
+
+ + +
+
+ + +
+ + +
+
+ + \ No newline at end of file