Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cloud transfer requires ETag + https redirector on port 8081 #80

Merged
merged 4 commits into from Jan 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion Dockerfile
Expand Up @@ -19,7 +19,8 @@ COPY --from=build /go/src/istio.io/fortio/ui/templates /usr/local/lib/fortio/tem
COPY --from=build /go/src/istio.io/fortio.bin /usr/local/bin/fortio
EXPOSE 8079
EXPOSE 8080
EXPOSE 8081
VOLUME /var/lib/istio/fortio
ENTRYPOINT ["/usr/local/bin/fortio"]
# start the server mode (grpc ping on 8079, http echo and UI on 8080) by default
# start the server mode (grpc ping on 8079, http echo and UI on 8080, redirector on 8081) by default
CMD ["server"]
8 changes: 8 additions & 0 deletions fortio_main.go
Expand Up @@ -105,6 +105,8 @@ var (

allowInitialErrorsFlag = flag.Bool("allow-initial-errors", false, "Allow and don't abort on initial warmup errors")
autoSaveFlag = flag.Bool("a", false, "Automatically save JSON result with filename based on labels and timestamp")
redirectFlag = flag.Int("redirect-port", 8081,
"Redirect all incoming traffic to https URL (need ingress to work properly). -1 means off.")
)

func main() {
Expand Down Expand Up @@ -133,8 +135,14 @@ func main() {
case "load":
fortioLoad()
case "report":
if *redirectFlag >= 0 {
go ui.RedirectToHTTPS(*redirectFlag)
}
ui.Report(*echoPortFlag, *staticDirFlag, *dataDirFlag)
case "server":
if *redirectFlag >= 0 {
go ui.RedirectToHTTPS(*redirectFlag)
}
go ui.Serve(*echoPortFlag, *echoDbgPathFlag, *uiPathFlag, *staticDirFlag, *dataDirFlag)
pingServer(*grpcPortFlag)
case "grpcping":
Expand Down
2 changes: 1 addition & 1 deletion periodic/periodic.go
Expand Up @@ -37,7 +37,7 @@ import (

const (
// Version is the overall package version (used to version json output too).
Version = "0.6.0"
Version = "0.6.1"
)

// DefaultRunnerOptions are the default values for options (do not mutate!).
Expand Down
46 changes: 42 additions & 4 deletions ui/uihandler.go
Expand Up @@ -41,6 +41,9 @@ import (
"istio.io/fortio/stats"
)

// TODO: move some of those in their own files/package (e.g data transfer TSV)
// and add unit tests.

var (
// UI and Debug prefix/paths (read in ui handler).
uiPath string // absolute (base)
Expand Down Expand Up @@ -386,7 +389,8 @@ func BrowseHandler(w http.ResponseWriter, r *http.Request) {

// LogRequest logs the incoming request, including headers when loglevel is verbose
func LogRequest(r *http.Request, msg string) {
log.Infof("%s: %v %v %v %v", msg, r.Method, r.URL, r.Proto, r.RemoteAddr)
log.Infof("%s: %v %v %v %v (%s)", msg, r.Method, r.URL, r.Proto, r.RemoteAddr,
r.Header.Get("X-Forwarded-Proto"))
if log.LogVerbose() {
for name, headers := range r.Header {
for _, h := range headers {
Expand Down Expand Up @@ -470,9 +474,13 @@ func sendTSVDataIndex(urlPrefix string, w http.ResponseWriter) {
gTSVCache.cachedResult = b.Bytes()
}
result := gTSVCache.cachedResult
lastModified := gTSVCache.cachedDirTime.Format(http.TimeFormat)
gTSVCacheMutex.Unlock()
log.Infof("Used cached %v to serve %d bytes TSV", useCache, len(result))
w.Header().Set("Content-Type", "text/plain; charset=UTF-8")
// Cloud transfer requires ETag
w.Header().Set("ETag", fmt.Sprintf("\"%s\"", lastModified))
w.Header().Set("Last-Modified", lastModified)
w.Write(result) // nolint: errcheck, gas
}

Expand All @@ -488,8 +496,13 @@ func LogAndFilterDataRequest(h http.Handler) http.Handler {
w.Header().Set("Access-Control-Allow-Origin", "*")
ext := "/index.tsv"
if strings.HasSuffix(path, ext) {
// TODO: what if we are reached through https ingress? or a different port
urlPrefix := "http://" + r.Host + path[:len(path)-len(ext)+1]
// Ingress effect:
// The Host header includes original host/port, only missing is the proto:
proto := r.Header.Get("X-Forwarded-Proto")
if len(proto) == 0 {
proto = "http"
}
urlPrefix := proto + "://" + r.Host + path[:len(path)-len(ext)+1]
log.LogVf("Prefix is '%s'", urlPrefix)
sendTSVDataIndex(urlPrefix, w)
return
Expand Down Expand Up @@ -612,6 +625,31 @@ func Report(port int, staticRsrcDir string, datadir string) {
fsd := http.FileServer(http.Dir(dataDir))
http.Handle(uiPath+"data/", LogAndFilterDataRequest(http.StripPrefix(uiPath+"data", fsd)))
if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
log.Critf("Error starting server: %v", err)
log.Critf("Error starting report server: %v", err)
}
}

// -- Redirection to https feature --

// RedirectToHTTPSHandler handler sends a redirect to same URL with https.
func RedirectToHTTPSHandler(w http.ResponseWriter, r *http.Request) {
dest := "https://" + r.Host + r.URL.String()
LogRequest(r, "Redirecting to "+dest)
http.Redirect(w, r, dest, http.StatusSeeOther)
}

// RedirectToHTTPS Sets up a redirector to https on the given port.
// (Do not create a loop, make sure this is addressed from an ingress)
func RedirectToHTTPS(port int) {
m := http.NewServeMux()
m.HandleFunc("/", RedirectToHTTPSHandler)
s := &http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: m,
}
fmt.Printf("Https redirector running on %v\n", s.Addr)
if err := s.ListenAndServe(); err != nil {
log.Critf("Error starting report server: %v", err)
}
fmt.Printf("Not reached, https redirector exiting - was on %v\n", s.Addr)
}