summaryrefslogtreecommitdiff
path: root/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'main.go')
-rw-r--r--main.go91
1 files changed, 88 insertions, 3 deletions
diff --git a/main.go b/main.go
index dad6584..75b60f9 100644
--- a/main.go
+++ b/main.go
@@ -1,17 +1,20 @@
package main
import (
+ "bytes"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
+ "net/url"
"os"
"strings"
"time"
"github.com/nats-io/nats.go"
+ "github.com/nats-io/nats.go/micro"
)
// printHelp outputs the usage information.
@@ -29,6 +32,46 @@ func printHelp() {
fmt.Println(" HTTP_PORT - HTTP port to listen on (default: 8080)")
}
+// URL to NATS subject conversion
+func URLToNATS(urlPath string) (string, error) {
+ segments := strings.Split(strings.Trim(urlPath, "/"), "/")
+ for i, seg := range segments {
+ // Decode existing encoding first to prevent double-encoding
+ unescaped, err := url.PathUnescape(seg)
+ if err != nil {
+ return "", fmt.Errorf("failed to unescape segment: %w", err)
+ }
+
+ // Encode special NATS-sensitive characters
+ encoded := url.PathEscape(unescaped)
+ encoded = strings.ReplaceAll(encoded, ".", "%2E") // Critical for token separation
+ encoded = strings.ReplaceAll(encoded, "*", "%2A") // Wildcard protection
+ encoded = strings.ReplaceAll(encoded, ">", "%3E") // Wildcard protection
+
+ segments[i] = encoded
+ }
+ return strings.Join(segments, "."), nil
+}
+
+// NATS subject to URL conversion
+func NATSToURL(natsSubject string) (string, error) {
+ tokens := strings.Split(natsSubject, ".")
+ for i, token := range tokens {
+ // Reverse the special character encoding
+ decoded := strings.ReplaceAll(token, "%2E", ".")
+ decoded = strings.ReplaceAll(decoded, "%2A", "*")
+ decoded = strings.ReplaceAll(decoded, "%3E", ">")
+
+ // Unescape remaining URL encoding
+ unescaped, err := url.PathUnescape(decoded)
+ if err != nil {
+ return "", fmt.Errorf("failed to unescape token: %w", err)
+ }
+ tokens[i] = unescaped
+ }
+ return "/" + strings.Join(tokens, "/"), nil
+}
+
func main() {
helpFlag := flag.Bool("help", false, "Display help information about available environment variables")
flag.Parse()
@@ -103,9 +146,14 @@ func main() {
domainParts := strings.ReplaceAll(host, ".", "_")
// Process path component
- path := strings.TrimPrefix(r.URL.Path, "/")
- // Replace all "." with "_" and then all "/" with ".".
- subjectPath := strings.ReplaceAll(strings.ReplaceAll(path, ".", "_"), "/", ".")
+ path := strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/"), "/")
+ subjectPath, err := URLToNATS(path)
+ if err != nil {
+ http.Error(w, "Error converting endpoint to NATS subject", http.StatusInternalServerError)
+ log.Println("Could not convert endpoint to NATS subject", err)
+ return
+
+ }
// Build final subject
subjectBase := "http"
@@ -161,6 +209,43 @@ func main() {
w.Write(reply.Data)
})
+ _, err = micro.AddService(nc, micro.Config{
+ Name: "http-nats-proxy",
+ Version: "0.1.0",
+ Endpoint: &micro.EndpointConfig{
+ Subject: "http.*.*.proxy.>",
+ Handler: micro.HandlerFunc(func(natsReq micro.Request) {
+ // http.host.method.proxy.host.endpoint.>
+ httpPath := natsReq.Headers()["X-HTTP-Path"][0]
+ httpReqURL := fmt.Sprintf("https:/%s", strings.TrimPrefix(httpPath, "/proxy"))
+ httpBody := bytes.NewReader(natsReq.Data())
+ httpMethod := natsReq.Headers()["X-HTTP-Method"][0]
+
+ // Create a new request
+ httpReq, err := http.NewRequest(httpMethod, httpReqURL, httpBody)
+ if err != nil {
+ log.Fatal(err)
+ }
+ client := &http.Client{}
+ resp, err := client.Do(httpReq)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer resp.Body.Close()
+
+ resBody, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ natsReq.Respond(resBody)
+ }),
+ },
+ })
+ if err != nil {
+ log.Fatal("Could not make NATS microservice:", err)
+ }
+
// Start the HTTP server
fmt.Println("Server is running on http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))