summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelonai <einebeere@gmail.com>2021-09-10 23:40:49 +0200
committerMelonai <einebeere@gmail.com>2021-09-10 23:43:57 +0200
commita32b9fe723c633cf5349bb0479d97e1f6d04445d (patch)
treef45869da615f5efcd0b2dd8d1baade6831dd3f4f
parent175da8f22cd791e81338fe61e6099125868cf5a0 (diff)
downloadportgate-a32b9fe723c633cf5349bb0479d97e1f6d04445d.tar.zst
portgate-a32b9fe723c633cf5349bb0479d97e1f6d04445d.zip
Refactor path into destination
-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")
-}