diff --git a/cmd/processRequest.go b/cmd/processRequest.go
index 7c44a9f..a4b9f14 100644
--- a/cmd/processRequest.go
+++ b/cmd/processRequest.go
@@ -14,6 +14,10 @@ import (
func processRequest(r *http.Request) responseWithHeader {
var response responseWithHeader
+ if response, ok := redirectInsecure(r); ok {
+ return *response
+ }
+
if dontCache(r) {
return get(r)
}
@@ -120,8 +124,56 @@ func dontCache(req *http.Request) bool {
// dont cache cyclic requests
loc := strings.Split(req.RequestURI, "?")[0]
- if strings.Contains(loc, ":") {
- return true
+ return strings.Contains(loc, ":")
+}
+
+// redirectInsecure returns redirection response, and bool value, if redirection was needed,
+// if the query comes from a browser, and it is insecure.
+//
+// Insecure queries are marked by the frontend web server
+// with X-Forwarded-Proto header:
+//
+// proxy_set_header X-Forwarded-Proto $scheme;
+//
+//
+func redirectInsecure(req *http.Request) (*responseWithHeader, bool) {
+ if isPlainTextAgent(req.Header.Get("User-Agent")) {
+ return nil, false
+ }
+
+ if strings.ToLower(req.Header.Get("X-Forwarded-Proto")) == "https" {
+ return nil, false
+ }
+
+ target := "https://" + req.Host + req.URL.Path
+ if len(req.URL.RawQuery) > 0 {
+ target += "?" + req.URL.RawQuery
+ }
+
+ body := []byte(fmt.Sprintf(`
+301 Moved
+301 Moved
+The document has moved
+here.
+
+`, target))
+
+ return &responseWithHeader{
+ InProgress: false,
+ Expires: time.Now().Add(time.Duration(randInt(1000, 1500)) * time.Second),
+ Body: body,
+ Header: http.Header{"Location": []string{target}},
+ StatusCode: 301,
+ }, true
+}
+
+// isPlainTextAgent returns true if userAgent is a plain-text agent
+func isPlainTextAgent(userAgent string) bool {
+ userAgentLower := strings.ToLower(userAgent)
+ for _, signature := range plainTextAgents {
+ if strings.Contains(userAgentLower, signature) {
+ return true
+ }
}
return false
}
diff --git a/cmd/srv.go b/cmd/srv.go
index aae32d5..b609b96 100644
--- a/cmd/srv.go
+++ b/cmd/srv.go
@@ -2,6 +2,7 @@ package main
import (
"context"
+ "fmt"
"log"
"net"
"net/http"
@@ -10,11 +11,26 @@ import (
lru "github.com/hashicorp/golang-lru"
)
+const serverPort = 8083
const uplinkSrvAddr = "127.0.0.1:9002"
const uplinkTimeout = 30
const prefetchInterval = 300
const lruCacheSize = 12800
+// plainTextAgents contains signatures of the plain-text agents
+var plainTextAgents = []string{
+ "curl",
+ "httpie",
+ "lwp-request",
+ "wget",
+ "python-requests",
+ "openbsd ftp",
+ "powershell",
+ "fetch",
+ "aiohttp",
+ "http_get",
+}
+
var lruCache *lru.Cache
type responseWithHeader struct {
@@ -65,5 +81,5 @@ func main() {
w.Write(response.Body)
})
- log.Fatal(http.ListenAndServe(":8082", nil))
+ log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", serverPort), nil))
}