/ pkg / web / hooks.go
hooks.go
 1  package web
 2  
 3  import (
 4  	"fmt"
 5  	"net/http"
 6  	"net/http/httputil"
 7  	"net/url"
 8  )
 9  
10  func (t InternalRouter) hookHandler(w http.ResponseWriter, r *http.Request) {
11  	var originIsPup bool = false
12  	originIP := getOriginIP(r)
13  	_, _, err := t.pm.FindPupByIP(originIP)
14  	if err == nil {
15  		originIsPup = true
16  	}
17  
18  	if !originIsPup {
19  		// you must be a pup!
20  		forbidden(w, "You are not a Pup we know about", originIP)
21  		return
22  	}
23  
24  	hookID := r.PathValue("hookID")
25  	handled := false
26  done:
27  	for _, pup := range t.pm.GetStateMap() {
28  		for _, hook := range pup.Hooks {
29  			if hookID == hook.ID {
30  				// check if the port is exposed first..
31  				exposed := false
32  				for _, ex := range pup.Manifest.Container.Exposes {
33  					if ex.Port == hook.Port {
34  						exposed = true
35  					}
36  				}
37  				if !exposed {
38  					sendErrorResponse(w, http.StatusUnauthorized, "Proxy to unexposed port unsupported")
39  					handled = true
40  					break done
41  				}
42  
43  				// proxy the request
44  				targetURL, err := url.Parse(fmt.Sprintf("http://%s:%d%s", pup.IP, hook.Port, hook.Path))
45  				if err != nil {
46  					sendErrorResponse(w, http.StatusInternalServerError, "couldn't compose proxy URL")
47  					handled = true
48  					break done
49  				}
50  				proxy := httputil.NewSingleHostReverseProxy(targetURL)
51  				proxy.Director = func(req *http.Request) {
52  					req.URL.Scheme = targetURL.Scheme
53  					req.URL.Host = targetURL.Host
54  					req.Header = r.Header
55  				}
56  				proxy.ServeHTTP(w, r)
57  
58  				handled = true
59  				break done
60  			}
61  		}
62  	}
63  
64  	if !handled {
65  		sendErrorResponse(w, http.StatusNotFound, "Hook not found")
66  	}
67  }