From 80b54f3b9d5e207316fb9e8f83dd1e90659b25d7 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Thu, 5 Sep 2019 13:36:42 -0600 Subject: Add original URI to request context; implement into fastcgi env --- modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go | 77 +++++++++-------------- modules/caddyhttp/server.go | 17 +++++ 2 files changed, 46 insertions(+), 48 deletions(-) diff --git a/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go b/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go index 35fef5f..090de25 100644 --- a/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go +++ b/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go @@ -19,12 +19,14 @@ import ( "crypto/tls" "fmt" "net/http" + "net/url" "path" "path/filepath" "strconv" "strings" "time" + "github.com/caddyserver/caddy/v2/modules/caddyhttp" "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy" "github.com/caddyserver/caddy/v2/modules/caddytls" @@ -37,25 +39,11 @@ func init() { // Transport facilitates FastCGI communication. type Transport struct { - ////////////////////////////// - // TODO: taken from v1 Handler type - - SoftwareName string - SoftwareVersion string - ServerName string - ServerPort string - - ////////////////////////// - // TODO: taken from v1 Rule type - - // The base path to match. Required. - // Path string - - // upstream load balancer - // balancer - - // Always process files with this extension with fastcgi. - // Ext string + // TODO: Populate these + softwareName string + softwareVersion string + serverName string + serverPort string // Use this directory as the fastcgi root directory. Defaults to the root // directory of the parent virtual host. @@ -67,16 +55,9 @@ type Transport struct { // PATH_INFO for the CGI script to use. SplitPath string `json:"split_path,omitempty"` - // If the URL ends with '/' (which indicates a directory), these index - // files will be tried instead. - // IndexFiles []string - // Environment Variables EnvVars [][2]string `json:"env,omitempty"` - // Ignored paths - // IgnoredSubPaths []string - // The duration used to set a deadline when connecting to an upstream. DialTimeout caddy.Duration `json:"dial_timeout,omitempty"` @@ -170,7 +151,6 @@ func (t Transport) buildEnv(r *http.Request) (map[string]string, error) { ip = strings.Replace(ip, "[", "", 1) ip = strings.Replace(ip, "]", "", 1) - // TODO: respect index files? or leave that to matcher/rewrite (I prefer that)? fpath := r.URL.Path // Split path in preparation for env variables. @@ -194,16 +174,17 @@ func (t Transport) buildEnv(r *http.Request) (map[string]string, error) { pathPrefix, _ := r.Context().Value(caddy.CtxKey("path_prefix")).(string) scriptName = path.Join(pathPrefix, scriptName) - // TODO: Disabled for now - // // Get the request URI from context. The context stores the original URI in case - // // it was changed by a middleware such as rewrite. By default, we pass the - // // original URI in as the value of REQUEST_URI (the user can overwrite this - // // if desired). Most PHP apps seem to want the original URI. Besides, this is - // // how nginx defaults: http://stackoverflow.com/a/12485156/1048862 - // reqURL, _ := r.Context().Value(httpserver.OriginalURLCtxKey).(url.URL) - - // // Retrieve name of remote user that was set by some downstream middleware such as basicauth. - // remoteUser, _ := r.Context().Value(httpserver.RemoteUserCtxKey).(string) + // Get the request URL from context. The context stores the original URL in case + // it was changed by a middleware such as rewrite. By default, we pass the + // original URI in as the value of REQUEST_URI (the user can overwrite this + // if desired). Most PHP apps seem to want the original URI. Besides, this is + // how nginx defaults: http://stackoverflow.com/a/12485156/1048862 + reqURL, ok := r.Context().Value(caddyhttp.OriginalURLCtxKey).(url.URL) + if !ok { + // some requests, like active health checks, don't add this to + // the request context, so we can just use the current URL + reqURL = *r.URL + } requestScheme := "http" if r.TLS != nil { @@ -224,19 +205,19 @@ func (t Transport) buildEnv(r *http.Request) (map[string]string, error) { "REMOTE_HOST": ip, // For speed, remote host lookups disabled "REMOTE_PORT": port, "REMOTE_IDENT": "", // Not used - // "REMOTE_USER": remoteUser, // TODO: - "REQUEST_METHOD": r.Method, - "REQUEST_SCHEME": requestScheme, - "SERVER_NAME": t.ServerName, - "SERVER_PORT": t.ServerPort, - "SERVER_PROTOCOL": r.Proto, - "SERVER_SOFTWARE": t.SoftwareName + "/" + t.SoftwareVersion, + "REMOTE_USER": "", // TODO: once there are authentication handlers, populate this + "REQUEST_METHOD": r.Method, + "REQUEST_SCHEME": requestScheme, + "SERVER_NAME": t.ServerName, + "SERVER_PORT": t.ServerPort, + "SERVER_PROTOCOL": r.Proto, + "SERVER_SOFTWARE": t.SoftwareName + "/" + t.SoftwareVersion, // Other variables - // "DOCUMENT_ROOT": rule.Root, - "DOCUMENT_URI": docURI, - "HTTP_HOST": r.Host, // added here, since not always part of headers - // "REQUEST_URI": reqURL.RequestURI(), // TODO: + "DOCUMENT_ROOT": t.Root, + "DOCUMENT_URI": docURI, + "HTTP_HOST": r.Host, // added here, since not always part of headers + "REQUEST_URI": reqURL.RequestURI(), "SCRIPT_FILENAME": scriptFilename, "SCRIPT_NAME": scriptName, } diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index 248e5f2..04935e6 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -20,6 +20,7 @@ import ( "log" "net" "net/http" + "net/url" "strconv" "strings" @@ -58,6 +59,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := context.WithValue(r.Context(), caddy.ReplacerCtxKey, repl) ctx = context.WithValue(ctx, ServerCtxKey, s) ctx = context.WithValue(ctx, VarCtxKey, make(map[string]interface{})) + ctx = context.WithValue(ctx, OriginalURLCtxKey, cloneURL(r.URL)) r = r.WithContext(ctx) // once the pointer to the request won't change @@ -228,6 +230,18 @@ type HTTPErrorConfig struct { Routes RouteList `json:"routes,omitempty"` } +// cloneURL makes a copy of r.URL and returns a +// new value that doesn't reference the original. +func cloneURL(u *url.URL) url.URL { + urlCopy := *u + if u.User != nil { + userInfo := new(url.Userinfo) + *userInfo = *u.User + urlCopy.User = userInfo + } + return urlCopy +} + // Context keys for HTTP request context values. const ( // For referencing the server instance @@ -235,4 +249,7 @@ const ( // For the request's variable table VarCtxKey caddy.CtxKey = "vars" + + // For the unmodified URL that originally came in with a request + OriginalURLCtxKey caddy.CtxKey = "original_url" ) -- cgit v1.2.3