summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--config.go4
-rw-r--r--destination.go75
-rw-r--r--handlers/handler.go33
-rw-r--r--handlers/passthrough.go4
-rw-r--r--handlers/portgate.go8
-rw-r--r--path.go80
6 files changed, 98 insertions, 106 deletions
diff --git a/config.go b/config.go
index 7630e87..f5fec33 100644
--- a/config.go
+++ b/config.go
@@ -45,9 +45,9 @@ func (c *Config) TargetAddress(port int) string {
 }
 
 // MakeUrl creates the URL on the destination host that the user wants to access.
-func (c *Config) MakeUrl(p Path) string {
+func (c *Config) MakeUrl(p Destination) string {
 	// TODO: Figure out what to do with TLS
-	return fmt.Sprintf("http://%s:%d%s", c.targetHost, p.DestinationIdentifier, p.ResourcePath)
+	return fmt.Sprintf("http://%s:%d%s", c.targetHost, p.Port, p.Path)
 }
 
 // CheckKey checks whether the givenKey matches the one in the config.
diff --git a/destination.go b/destination.go
new file mode 100644
index 0000000..d911e3e
--- /dev/null
+++ b/destination.go
@@ -0,0 +1,75 @@
+package portgate
+
+import (
+	"net/url"
+	"path"
+	"strconv"
+	"strings"
+)
+
+// Destination represents a routing destination the user gave.
+type Destination struct {
+	// Identifier to which port of the destination host the path points to and to which the
+	// user's request will be proxied to.
+	Port int
+	// The path without the port identifier.
+	// This is the path which will be requested from the destination.
+	Path string
+	IsPortgatePath bool
+}
+
+// ParseDestinationFromURL creates a Path from the requested URL.
+func DestinationFromURL(p string) Destination {
+	p = path.Clean("/" + p)
+
+	// Get first path part, which is the potential port identifier.
+	destinationIdentifierEnd := strings.Index(p[1:], "/") + 1
+
+	// If there is no '/' in the path, apart from the root, the first part is the entire path
+	if destinationIdentifierEnd == 0 {
+		destinationIdentifierEnd = len(p)
+	}
+
+	destinationIdentifier := p[1:destinationIdentifierEnd]
+
+	// We have to to check that destinationIdentifier is a port
+	port, err := strconv.Atoi(destinationIdentifier)
+	if err == nil {
+		// We got an identifier and can split the path
+		resourcePath := path.Clean("/" + p[destinationIdentifierEnd:])
+
+		return Destination{
+			Port: port,
+			Path: resourcePath,
+		}
+	} else {
+		destination := Destination{
+			Port: 0,
+			Path: p,
+		}
+
+		if strings.HasPrefix(destination.Path, "/_portgate") {
+			destination.IsPortgatePath = true
+			return destination
+		}
+
+		return destination
+	}
+}
+
+// DestinationFromReferer tries to create a Path from the Referer header of the request.
+func (d Destination) AddReferer(referer string) Destination {
+	u, err := url.Parse(referer)
+	if err != nil {
+		return Destination{}
+	}
+
+	// d has the correct resource path but the wrong port, so we create a new destination
+	// with the correct data from both.
+	newDestination := DestinationFromURL(u.Path)
+
+	return Destination{
+		Port: newDestination.Port,
+		Path: d.Path,
+	}
+}
\ No newline at end of file
diff --git a/handlers/handler.go b/handlers/handler.go
index d6e1b5b..7989766 100644
--- a/handlers/handler.go
+++ b/handlers/handler.go
@@ -42,34 +42,29 @@ func NewRequestHandler(config *portgate.Config, templates portgate.Templates) Re
 
 // HandleRequest handles all types of requests and delegates to more specific handlers.
 func (h *RequestHandler) HandleRequest(ctx *fasthttp.RequestCtx) {
-	path := portgate.ParsePath(string(ctx.Path()))
+	destination := portgate.DestinationFromURL(string(ctx.Path()))
 
-	if path.IsPortgatePath() {
-		h.handlePortgateRequest(ctx, path)
+	if destination.IsPortgatePath {
+		h.handlePortgateRequest(ctx, destination)
 		return
 	}
 
-	if path.DestinationIdentifier == -1 {
-		// We were not given a destination.
+	if destination.Port == 0 {
+		// Try to get the port from the Referer.
+		destination = destination.AddReferer(string(ctx.Request.Header.Referer()))
 
-		// Try to grab actual destination from Referer header.
-		// This can help us if the user followed an absolute link on a proxied page.
-		refererPath, err := portgate.ParsePathFromReferer(path, string(ctx.Request.Header.Referer()))
-		if err != nil || refererPath.DestinationIdentifier == -1 {
-			// The referer path also has no destination
+		// Still no port?
+		if destination.Port == 0 {
 			h.handleUnknownRequest(ctx)
-		} else {
-			// We found the destination from the referer path, so we
-			// redirect the user to the Portgate URL they should've requested.
-
-			portgateUrl := fmt.Sprintf("/%d%s", refererPath.DestinationIdentifier, refererPath.ResourcePath)
-			ctx.Redirect(portgateUrl, http.StatusTemporaryRedirect)
+			return
 		}
-	} else {
-		// We were given a port, so we have to pass the request through to the destination host.
 
-		h.handlePassthroughRequest(ctx, path)
+		portgateUrl := fmt.Sprintf("/%d%s", destination.Port, destination.Path)
+		ctx.Redirect(portgateUrl, http.StatusTemporaryRedirect)
+		return
 	}
+
+	h.handlePassthroughRequest(ctx, destination)
 }
 
 // handleUnknownRequest handles any request which could not be processed due to missing
diff --git a/handlers/passthrough.go b/handlers/passthrough.go
index 3f8aafc..30cc7df 100644
--- a/handlers/passthrough.go
+++ b/handlers/passthrough.go
@@ -9,7 +9,7 @@ import (
 // handlePassthroughRequest handles requests which are supposed to be proxied to the destination host.
 // If the user is authorized they are allowed to pass, otherwise they should be redirected to
 // the authentication page. (/_portgate)
-func (h *RequestHandler) handlePassthroughRequest(ctx *fasthttp.RequestCtx, p portgate.Path) {
+func (h *RequestHandler) handlePassthroughRequest(ctx *fasthttp.RequestCtx, p portgate.Destination) {
 	// TODO: Check whether port is allowed to be accessed.
 
 	// Check whether given cookie is ok, if not redirect to the authentication page.
@@ -21,7 +21,7 @@ func (h *RequestHandler) handlePassthroughRequest(ctx *fasthttp.RequestCtx, p po
 	// We reuse the request given to us by the user with minor changes to route it to the
 	// destination host.
 	ctx.Request.SetRequestURI(h.config.MakeUrl(p))
-	ctx.Request.Header.SetHost(h.config.TargetAddress(p.DestinationIdentifier))
+	ctx.Request.Header.SetHost(h.config.TargetAddress(p.Port))
 
 	// We pipe the response given to us by the destination host back to the user.
 	// Since it's possible that we get a redirect, we take this into account,
diff --git a/handlers/portgate.go b/handlers/portgate.go
index 6e002e7..2cf8e13 100644
--- a/handlers/portgate.go
+++ b/handlers/portgate.go
@@ -1,16 +1,18 @@
 package handlers
 
 import (
-	"github.com/valyala/fasthttp"
 	"net/http"
 	"portgate"
+	"strings"
 	"time"
+
+	"github.com/valyala/fasthttp"
 )
 
 // handlePortgateRequest handles all Portgate specific request for either showing Portgate
 // specific pages or handling creation of authorization tokens.
-func (h *RequestHandler) handlePortgateRequest(ctx *fasthttp.RequestCtx, path portgate.Path) {
-	if path.IsPortgateStaticPath() {
+func (h *RequestHandler) handlePortgateRequest(ctx *fasthttp.RequestCtx, destination portgate.Destination) {
+	if strings.HasPrefix(destination.Path, "/_portgate/static") {
 		h.staticHandler(ctx)
 	} else {
 		// TODO: Implement authentication, authorization
diff --git a/path.go b/path.go
deleted file mode 100644
index 82a8353..0000000
--- a/path.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package portgate
-
-import (
-	"net/url"
-	"path"
-	"strconv"
-	"strings"
-)
-
-// Path represents a routing destination the user gave.
-type Path struct {
-	// Identifier to which port of the destination host the path points to and to which the
-	// user's request will be proxied to.
-	// If there was no identifier given it's -1.
-	DestinationIdentifier int
-	// The path without the port identifier.
-	// This is the path which will be requested from the destination.
-	ResourcePath string
-}
-
-// ParsePath creates a Path from the requested URL.
-func ParsePath(p string) Path {
-	p = path.Clean("/" + p)
-
-	// Get first path part, which is the destinationIdentifier
-
-	destinationIdentifierEnd := strings.Index(p[1:], "/") + 1
-
-	// If there is no '/' at in the path, apart from the root, the first part is the entire path
-	if destinationIdentifierEnd == 0 {
-		destinationIdentifierEnd = len(p)
-	}
-
-	destinationIdentifier := p[1:destinationIdentifierEnd]
-
-	// We have to to check that destinationIdentifier is a port
-	port, err := strconv.Atoi(destinationIdentifier)
-	if err == nil {
-		// We got an identifier and can split the path
-
-		resourcePath := path.Clean("/" + p[destinationIdentifierEnd:])
-		return Path{
-			DestinationIdentifier: port,
-			ResourcePath:          resourcePath,
-		}
-	} else {
-		// We got some other path without an identifier
-
-		return Path{
-			DestinationIdentifier: -1,
-			ResourcePath:          p,
-		}
-	}
-}
-
-// ParsePathFromReferer tries to create a Path from the Referer header of the request.
-func ParsePathFromReferer(p Path, r string) (Path, error) {
-	u, err := url.Parse(r)
-	if err != nil {
-		return Path{}, err
-	}
-
-	// p has the correct resource path but the wrong port, so we create a new path
-	// with the correct data from both.
-	rp := ParsePath(u.Path)
-	return Path{
-		DestinationIdentifier: rp.DestinationIdentifier,
-		ResourcePath:          p.ResourcePath,
-	}, nil
-}
-
-// IsPortgatePath returns whether the Path goes to Portgate.
-func (p *Path) IsPortgatePath() bool {
-	return p.DestinationIdentifier == -1 && strings.HasPrefix(p.ResourcePath, "/_portgate")
-}
-
-// IsPortgateStaticPath returns whether the Path goes to the Portgate static files.
-func (p *Path) IsPortgateStaticPath() bool {
-	return p.DestinationIdentifier == -1 && strings.HasPrefix(p.ResourcePath, "/_portgate/static")
-}