diff --git a/assets/templates/html/index.html.tmpl b/assets/templates/html/index.html.tmpl index 367a347..edaa676 100644 --- a/assets/templates/html/index.html.tmpl +++ b/assets/templates/html/index.html.tmpl @@ -28,10 +28,10 @@ the command line.

Command line API

     # Upload a file
-    curl -F'file=@yourfile.png' {{.Host}}
+    curl -F'file=@yourfile.png' {{.RootURL}}
 
     # Shorten a URL
-    curl -F'shorten=http://example.com/some/long/url' {{.Host}}
+    curl -F'shorten=http://example.com/some/long/url' {{.RootURL}}
 
     # The first line of the result will contain the shortened URL.
     #
@@ -39,6 +39,6 @@ the command line.
     # information on how to delete the shortened object.
 
     # To upload a file and only extract the shortened URL (i.e. throw away the rest)
-    curl -F'file=@yourfile.png' {{.Host}} | head -n 1
+    curl -F'file=@yourfile.png' {{.RootURL}} | head -n 1
 
{{end}} diff --git a/assets/templates/html/pasteMeta.html.tmpl b/assets/templates/html/pasteMeta.html.tmpl index 5c50084..e697c30 100644 --- a/assets/templates/html/pasteMeta.html.tmpl +++ b/assets/templates/html/pasteMeta.html.tmpl @@ -4,10 +4,10 @@ {{define "body"}}
-{{.Host}}/{{.Paste.Key}}{{.FileExt}}
+{{.RootURL}}/{{.Paste.Key}}{{.FileExt}}
 ---
 {{if and (ne .Paste.State.String "deleted") .CanDeleteBool}}
-with delete token: {{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}
+with delete token: {{.RootURL}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}
 {{else -}}
 with delete token: <unknown>
 {{end -}}
@@ -22,7 +22,7 @@ delete token: {{.CanDelete}}
 
 {{if and (ne .Paste.State.String "deleted") .CanDeleteBool}}
 ```
-curl --request "DELETE" "{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}"
+curl --request "DELETE" "{{.RootURL}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}"
 ```
 
{{end}} diff --git a/assets/templates/txt/index.txt.tmpl b/assets/templates/txt/index.txt.tmpl index 0dd996d..dd5e8e0 100644 --- a/assets/templates/txt/index.txt.tmpl +++ b/assets/templates/txt/index.txt.tmpl @@ -7,10 +7,10 @@ the command line. ## USAGE # Upload a file - curl -F'file=@yourfile.png' {{.Host}} + curl -F'file=@yourfile.png' {{.RootURL}} # Shorten a URL - curl -F'shorten=http://example.com/some/long/url' {{.Host}} + curl -F'shorten=http://example.com/some/long/url' {{.RootURL}} # The first line of the result will contain the shortened URL. # @@ -18,4 +18,4 @@ the command line. # information on how to delete the shortened object. # To upload a file and only extract the shortened URL (i.e. throw away the rest) - curl -F'file=@yourfile.png' {{.Host}} | head -n 1 \ No newline at end of file + curl -F'file=@yourfile.png' {{.RootURL}} | head -n 1 diff --git a/assets/templates/txt/pasteMeta.txt.tmpl b/assets/templates/txt/pasteMeta.txt.tmpl index c2c5ee5..75319e7 100644 --- a/assets/templates/txt/pasteMeta.txt.tmpl +++ b/assets/templates/txt/pasteMeta.txt.tmpl @@ -1,7 +1,7 @@ -{{.Host}}/{{.Paste.Key}}{{.FileExt}} +{{.RootURL}}/{{.Paste.Key}}{{.FileExt}} --- {{if and (ne .Paste.State.String "deleted") .CanDeleteBool}} -with delete token: {{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}} +with delete token: {{.RootURL}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}} {{else -}} with delete token: {{end -}}type: {{.Paste.Type}} @@ -16,6 +16,6 @@ delete token: {{.CanDelete}} {{if and (ne .Paste.State.String "deleted") .CanDeleteBool}} ``` # To delete this {{.Paste.Type}}, execute: -curl --request "DELETE" "{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}" +curl --request "DELETE" "{{.RootURL}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}" ``` {{end}} diff --git a/cmd/rushlink/main.go b/cmd/rushlink/main.go index f5ea838..36ae1cc 100644 --- a/cmd/rushlink/main.go +++ b/cmd/rushlink/main.go @@ -13,7 +13,7 @@ var ( fileStorePath = flag.String("file-store", "", "path to the directory where uploaded files will be stored") httpListen = flag.String("listen", "127.0.0.1:8000", "listen address (host:port)") metricsListen = flag.String("metrics_listen", "127.0.0.1:58614", "listen address for metrics (host:port)") - hostURL = flag.String("host", "", "host root (defaults to using the request 'Host' header with HTTPS") + rootURL = flag.String("root_url", "", "host root (example: 'https://example.com', uses an educated guess if omitted)") ) func main() { @@ -30,5 +30,5 @@ func main() { defer database.Close() go rushlink.StartMetricsServer(*metricsListen, database, filestore) - rushlink.StartMainServer(*httpListen, database, filestore, hostURL) + rushlink.StartMainServer(*httpListen, database, filestore, *rootURL) } diff --git a/router.go b/router.go index 0ca2743..8d04d3e 100644 --- a/router.go +++ b/router.go @@ -19,13 +19,13 @@ const urlKeyExpr = "{key:[A-Za-z0-9-_]{4,}}" const urlKeyWithExtExpr = urlKeyExpr + "{ext:\\.[A-Za-z0-9-_]+}" type rushlink struct { - db *db.Database - fs *db.FileStore - host *url.URL + db *db.Database + fs *db.FileStore + rootURL *url.URL } -func (rl *rushlink) Host() *url.URL { - return rl.host +func (rl *rushlink) RootURL() *url.URL { + return rl.rootURL } func (rl *rushlink) recoveryMiddleware(next http.Handler) http.Handler { @@ -80,21 +80,19 @@ func (w *statusResponseWriter) WriteHeader(statusCode int) { } // StartMainServer starts the main http server listening on addr. -func StartMainServer(addr string, db *db.Database, fs *db.FileStore, rawhost *string) { - var host *url.URL - if rawhost != nil { +func StartMainServer(addr string, db *db.Database, fs *db.FileStore, rawRootURL string) { + var rootURL *url.URL + if rawRootURL != "" { var err error - host, err = url.Parse(*rawhost) + rootURL, err = url.Parse(rawRootURL) if err != nil { - log.Fatalln(errors.Wrap(err, "could not parse host flag")) + log.Fatalln(errors.Wrap(err, "could not parse rootURL flag")) } - } else { - log.Println("warning: the --host flag will be required in the future") } rl := rushlink{ - db: db, - fs: fs, - host: host, + db: db, + fs: fs, + rootURL: rootURL, } // Initialize Gorilla router diff --git a/views.go b/views.go index 88cdfee..61bfa42 100644 --- a/views.go +++ b/views.go @@ -21,7 +21,7 @@ import ( "github.com/pkg/errors" ) -const defaultScheme = "https" +const defaultScheme = "http" // Plain text templates var textBaseTemplate *text.Template = text.Must(text.New("").Parse(string(MustAsset("templates/txt/base.txt.tmpl")))) @@ -107,7 +107,7 @@ func (rl *rushlink) render(w http.ResponseWriter, r *http.Request, tmplName stri } // Add the request to the template data - mapExtend(data, "Host", rl.resolveHost(r)) + mapExtend(data, "RootURL", rl.resolveRootURL(r)) mapExtend(data, "Request", r) switch contentType { @@ -165,19 +165,38 @@ func (rl *rushlink) renderInternalServerError(w http.ResponseWriter, r *http.Req rl.renderError(w, r, http.StatusInternalServerError, msg) } -// resolveHost constructs the `scheme://host` part of rushlinks public API. +// resolveRootURL constructs the `scheme://host` part of rushlinks public API. // -// If the `--host` flag is set, it will return that URL. +// If the `--root_url` flag is set, it will return that URL. // Otherwise, this function will return 'https://{Host}', where `{Host}` is // the value provided by the client in the HTTP `Host` header. This value may // be invalid, but it is impossible to handle this error (because we *cannot* // know the real host). -func (rl *rushlink) resolveHost(r *http.Request) string { - rlHost := rl.Host() +func (rl *rushlink) resolveRootURL(r *http.Request) string { + rlHost := rl.RootURL() if rlHost != nil { + // Root URL overridden by command line arguments + log.Println("override") return rlHost.String() } - return defaultScheme + r.Host + + // Guess scheme + scheme := defaultScheme + forwardedScheme := r.Header.Get("X-Forwarded-Proto") + switch forwardedScheme { + case "http": + scheme = "http" + break + case "https": + scheme = "https" + break + } + // Guess host + host := r.Host + if forwardedHost := r.Header.Get("X-Forwarded-Host"); forwardedHost != "" { + host = forwardedHost + } + return scheme + "://" + host } // Try to resolve the preferred content-type for the response to this request.