summaryrefslogtreecommitdiff
path: root/internal/cmd/root.go
blob: 6d9c27120ff6cf5b50d40179e1c1ec4f03256c68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package cmd

import (
	"context"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"time"

	"github.com/Wacky404/rpserver/internal/auth"
)

func ExecuteServer(portNum string) error {
    // don't know if want to keep handlers in here
	http.HandleFunc("/proxy", handleProxy)

	log.Printf("Reverse Proxy running on :%v", portNum)
	err := http.ListenAndServe(":"+portNum, nil)

	return err
}

func handleProxy(w http.ResponseWriter, r *http.Request) {
	if !auth.Verifyrequest(r) {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}

	backendURL, err := getBackendURL(r)
	if err != nil {
		http.Error(w, "Backend URL not provided", http.StatusBadRequest)
		return
	}

	proxy := httputil.NewSingleHostReverseProxy(backendURL)

	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()

	r = r.WithContext(ctx) // attaching the new ctx to request

	proxy.Director = func(req *http.Request) {
		req.URL.Scheme = backendURL.Scheme
		req.URL.Host = backendURL.Host
		req.URL.Path = backendURL.Path
		req.Host = backendURL.Host
	}

	done := make(chan struct{})
	go func() {
		proxy.ServeHTTP(w, r) // Forward the request
		close(done)
	}()

	select {
	case <-ctx.Done(): // if context timout occurs
		http.Error(w, "Request timed out", http.StatusGatewayTimeout)
		log.Println("Request to", r.URL.Path, "timed out...balls")
	case <-done: // if request completes successfully
	}
}

func getBackendURL(r *http.Request) (*url.URL, error) {
	backend := r.Header.Get("X-Backend-URL") // extraction of backend from request

	if backend == "" {
		return nil, http.ErrNoLocation // error if no backend is in request
	}

	return url.Parse(backend) // parse and return the backend url
}