diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 14:59:07 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 14:59:07 +0300 |
commit | 8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch) | |
tree | 544930fb309b30317ae9797a9683768705d664c4 /workhorse/internal/upstream/upstream.go | |
parent | 4b1de649d0168371549608993deac953eb692019 (diff) |
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'workhorse/internal/upstream/upstream.go')
-rw-r--r-- | workhorse/internal/upstream/upstream.go | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/workhorse/internal/upstream/upstream.go b/workhorse/internal/upstream/upstream.go new file mode 100644 index 00000000000..fd3f6191a5a --- /dev/null +++ b/workhorse/internal/upstream/upstream.go @@ -0,0 +1,123 @@ +/* +The upstream type implements http.Handler. + +In this file we handle request routing and interaction with the authBackend. +*/ + +package upstream + +import ( + "fmt" + + "net/http" + "strings" + + "github.com/sirupsen/logrus" + "gitlab.com/gitlab-org/labkit/correlation" + + "gitlab.com/gitlab-org/gitlab-workhorse/internal/config" + "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper" + "gitlab.com/gitlab-org/gitlab-workhorse/internal/upload" + "gitlab.com/gitlab-org/gitlab-workhorse/internal/upstream/roundtripper" + "gitlab.com/gitlab-org/gitlab-workhorse/internal/urlprefix" +) + +var ( + DefaultBackend = helper.URLMustParse("http://localhost:8080") + requestHeaderBlacklist = []string{ + upload.RewrittenFieldsHeader, + } +) + +type upstream struct { + config.Config + URLPrefix urlprefix.Prefix + Routes []routeEntry + RoundTripper http.RoundTripper + CableRoundTripper http.RoundTripper + accessLogger *logrus.Logger +} + +func NewUpstream(cfg config.Config, accessLogger *logrus.Logger) http.Handler { + up := upstream{ + Config: cfg, + accessLogger: accessLogger, + } + if up.Backend == nil { + up.Backend = DefaultBackend + } + if up.CableBackend == nil { + up.CableBackend = up.Backend + } + if up.CableSocket == "" { + up.CableSocket = up.Socket + } + up.RoundTripper = roundtripper.NewBackendRoundTripper(up.Backend, up.Socket, up.ProxyHeadersTimeout, cfg.DevelopmentMode) + up.CableRoundTripper = roundtripper.NewBackendRoundTripper(up.CableBackend, up.CableSocket, up.ProxyHeadersTimeout, cfg.DevelopmentMode) + up.configureURLPrefix() + up.configureRoutes() + + var correlationOpts []correlation.InboundHandlerOption + if cfg.PropagateCorrelationID { + correlationOpts = append(correlationOpts, correlation.WithPropagation()) + } + + handler := correlation.InjectCorrelationID(&up, correlationOpts...) + return handler +} + +func (u *upstream) configureURLPrefix() { + relativeURLRoot := u.Backend.Path + if !strings.HasSuffix(relativeURLRoot, "/") { + relativeURLRoot += "/" + } + u.URLPrefix = urlprefix.Prefix(relativeURLRoot) +} + +func (u *upstream) ServeHTTP(w http.ResponseWriter, r *http.Request) { + helper.FixRemoteAddr(r) + + helper.DisableResponseBuffering(w) + + // Drop RequestURI == "*" (FIXME: why?) + if r.RequestURI == "*" { + helper.HTTPError(w, r, "Connection upgrade not allowed", http.StatusBadRequest) + return + } + + // Disallow connect + if r.Method == "CONNECT" { + helper.HTTPError(w, r, "CONNECT not allowed", http.StatusBadRequest) + return + } + + // Check URL Root + URIPath := urlprefix.CleanURIPath(r.URL.Path) + prefix := u.URLPrefix + if !prefix.Match(URIPath) { + helper.HTTPError(w, r, fmt.Sprintf("Not found %q", URIPath), http.StatusNotFound) + return + } + + // Look for a matching route + var route *routeEntry + for _, ro := range u.Routes { + if ro.isMatch(prefix.Strip(URIPath), r) { + route = &ro + break + } + } + + if route == nil { + // The protocol spec in git/Documentation/technical/http-protocol.txt + // says we must return 403 if no matching service is found. + helper.HTTPError(w, r, "Forbidden", http.StatusForbidden) + return + } + + for _, h := range requestHeaderBlacklist { + r.Header.Del(h) + } + + route.handler.ServeHTTP(w, r) +} |