hostsplitter/hostsplitter.go

123 lines
2.8 KiB
Go

package main
import (
"fmt"
"net/http"
"net/http/httputil"
"os"
"strings"
"time"
"github.com/VividCortex/godaemon"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
routedHostnames map[string]int
// Sites are the enabled sites
Sites []Site
// HTTPClient is the http client
HTTPClient http.Client
)
var (
logFileLoc = kingpin.Flag("log", "Location of the log file").Default("stdout").String()
daemonize = kingpin.Flag("daemon", "If daemonized, the program will run in the background.").Default("false").Bool()
sitesLoc = kingpin.Flag("sites_dir", "Location of site files").Short('h').Default("/etc/hostsplitter/").String()
bindAddr = kingpin.Flag("bind", "Bind address").Short('b').Default(":80").String()
)
func main() {
HTTPClient = http.Client{}
kingpin.Parse()
fmt.Println("Starting hostsplitter")
if *logFileLoc != "stdout" {
logFile, err := os.OpenFile(*logFileLoc, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0640)
defer logFile.Close()
if err != nil {
fmt.Println("error opening file: %v", err)
}
fmt.Println("Using ", *logFileLoc, " for logging")
//log.SetOutput(logFile)
}
if *daemonize {
fmt.Println("Daemonizing... Bye Bye")
godaemon.MakeDaemon(&godaemon.DaemonAttr{})
}
LoadConfig()
go SignalHandler()
r := new(revProx)
fmt.Println(http.ListenAndServe(*bindAddr, r))
}
type revProx struct{}
func (p *revProx) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if i, ok := routedHostnames[string(r.Host)]; ok {
reverseProxy := new(httputil.ReverseProxy)
reverseProxy.Director = func(r *http.Request) {
r.Header.Set("X-Hostsplitter-Secret", Sites[i].Secret)
r.Header.Set("Host", r.Host)
r.URL.Scheme = "http"
r.URL.Host = Sites[i].GetBackend()
r.RequestURI = ""
HTTPLogger(r, http.StatusOK)
}
reverseProxy.ServeHTTP(w, r)
} else {
HTTPLogger(r, http.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Bad Request"))
}
}
const apacheFormatPattern = "%s - - [%s] \"%s %s %s\" %d %d \"%s\" \"%s\" %.4f\n"
// HTTPLogger logs an http request
func HTTPLogger(r *http.Request, status int) {
if *logFileLoc != "stdout" {
logFile, err := os.OpenFile(*logFileLoc, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0640)
defer logFile.Close()
if err != nil {
fmt.Println("error opening file: %v", err)
}
timeFormatted := time.Now().Format("02/Jan/2006 03:04:05")
clientIP := r.RemoteAddr
if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
clientIP = clientIP[:colon]
}
referer := r.Referer()
if referer == "" {
referer = "-"
}
userAgent := r.UserAgent()
if userAgent == "" {
userAgent = "-"
}
fmt.Fprint(logFile, fmt.Sprintf(
apacheFormatPattern,
clientIP,
timeFormatted,
r.Method,
r.RequestURI,
r.Proto,
status,
0,
referer,
userAgent,
0.00,
))
}
}