Example #1
0
func (u *Upstream) FilterRequest(request *falcore.Request) (res *http.Response) {
	var err os.Error
	req := request.HttpRequest

	// Force the upstream to use http
	if u.ForceHttp || req.URL.Scheme == "" {
		req.URL.Scheme = "http"
		req.URL.Host = req.Host
	}
	before := time.Nanoseconds()
	req.Header.Set("Connection", "Keep-Alive")
	res, err = u.transport.RoundTrip(req)
	diff := falcore.TimeDiff(before, time.Nanoseconds())
	if err != nil {
		if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
			falcore.Error("%s Upstream Timeout error: %v", request.ID, err)
			res = falcore.SimpleResponse(req, 504, nil, "Gateway Timeout\n")
			request.CurrentStage.Status = 2 // Fail
		} else {
			falcore.Error("%s Upstream error: %v", request.ID, err)
			res = falcore.SimpleResponse(req, 502, nil, "Bad Gateway\n")
			request.CurrentStage.Status = 2 // Fail
		}
	}
	falcore.Debug("%s [%s] [%s%s] s=%d Time=%.4f", request.ID, req.Method, u.host, req.RawURL, res.StatusCode, diff)
	return
}
Example #2
0
func (u *Upstream) ping() (up bool, ok bool) {
	if u.PingPath != "" {
		// the url must be syntactically valid for this to work but the host will be ignored because we
		// are overriding the connection always
		request, err := http.NewRequest("GET", "http://localhost"+u.PingPath, nil)
		request.Header.Set("Connection", "Keep-Alive") // not sure if this should be here for a ping
		if err != nil {
			falcore.Error("Bad Ping request: %v", err)
			return false, true
		}
		res, err := u.transport.RoundTrip(request)

		if err != nil {
			falcore.Error("Failed Ping to %v:%v: %v", u.Host, u.Port, err)
			return false, true
		} else {
			res.Body.Close()
		}
		if res.StatusCode == 200 {
			return true, true
		}
		falcore.Error("Failed Ping to %v:%v: %v", u.Host, u.Port, res.Status)
		// bad status
		return false, true
	}
	return false, false
}
Example #3
0
// The config consists of a map of the servers in the pool in the format host_or_ip:port
// where port is optional and defaults to 80.  The map value is an int with the weight
// only 0 and 1 are supported weights (0 disables a server and 1 enables it)
func NewUpstreamPool(name string, config []UpstreamEntryConfig) *UpstreamPool {
	up := new(UpstreamPool)
	up.pool = make([]*UpstreamEntry, len(config))
	up.Name = name
	up.nextUpstream = make(chan *UpstreamEntry)
	up.weightMutex = new(sync.RWMutex)
	up.shutdown = make(chan int)
	up.pinger = time.NewTicker(3e9) // 3s

	// create the pool
	for i, uec := range config {
		parts := strings.Split(uec.HostPort, ":")
		upstreamHost := parts[0]
		upstreamPort := 80
		if len(parts) > 1 {
			var err os.Error
			upstreamPort, err = strconv.Atoi(parts[1])
			if err != nil {
				upstreamPort = 80
				falcore.Error("UpstreamPool Error converting port to int for", upstreamHost, ":", err)
			}
		}
		ups := NewUpstream(upstreamHost, upstreamPort, uec.ForceHttp)
		ups.PingPath = uec.PingPath
		ue := new(UpstreamEntry)
		ue.Upstream = ups
		ue.Weight = uec.Weight
		up.pool[i] = ue
	}
	go up.nextServer()
	go up.pingUpstreams()
	return up
}
Example #4
0
func (f *Filter) FilterRequest(req *falcore.Request) (res *http.Response) {
	// Clean asset path
	asset_path := filepath.Clean(filepath.FromSlash(req.HttpRequest.URL.Path))

	// Resolve PathPrefix
	if strings.HasPrefix(asset_path, f.PathPrefix) {
		asset_path = asset_path[len(f.PathPrefix):]
	} else {
		falcore.Debug("%v doesn't match prefix %v", asset_path, f.PathPrefix)
		res = falcore.SimpleResponse(req.HttpRequest, 404, nil, "Not found.")
		return
	}

	// Resolve FSBase
	if f.BasePath != "" {
		asset_path = filepath.Join(f.BasePath, asset_path)
	} else {
		falcore.Error("file_filter requires a BasePath")
		return falcore.SimpleResponse(req.HttpRequest, 500, nil, "Server Error\n")
	}

	var fileSize int64
	if stat, err := os.Stat(asset_path); err == nil {
		fileSize = stat.Size
	} else {
		falcore.Debug("Can't stat %v: %v", asset_path, err)
		return falcore.SimpleResponse(req.HttpRequest, 404, nil, "File not found\n")
	}

	// Open File
	if file, err := os.Open(asset_path); err == nil {
		// Make sure it's an actual file
		if stat, err := file.Stat(); err == nil && stat.IsRegular() {
			res = &http.Response{
				Request:       req.HttpRequest,
				StatusCode:    200,
				Proto:         "HTTP/1.1",
				Body:          file,
				Header:        make(http.Header),
				ContentLength: fileSize,
			}
			if ct := mime.TypeByExtension(filepath.Ext(asset_path)); ct != "" {
				res.Header.Set("Content-Type", ct)
			}
		} else {
			file.Close()
			return falcore.SimpleResponse(req.HttpRequest, 404, nil, "File not found\n")
		}
	} else {
		falcore.Debug("Can't open %v: %v", asset_path, err)
		res = falcore.SimpleResponse(req.HttpRequest, 404, nil, "File not found\n")
	}

	return
}
Example #5
0
func NewUpstream(host string, port int, forceHttp bool) *Upstream {
	u := new(Upstream)
	u.Host = host
	u.Port = port
	u.ForceHttp = forceHttp
	ips, err := net.LookupIP(host)
	var ip net.IP = nil
	for i := range ips {
		ip = ips[i].To4()
		if ip != nil {
			break
		}
	}
	if err == nil && ip != nil {
		u.tcpaddr = new(net.TCPAddr)
		u.tcpaddr.Port = port
		u.tcpaddr.IP = ip
	} else {
		falcore.Warn("Can't get IP addr for %v: %v", host, err)
	}
	u.Timeout = 60e9
	u.host = fmt.Sprintf("%v:%v", u.Host, u.Port)

	u.transport = new(http.Transport)
	u.transport.Dial = func(n, addr string) (c net.Conn, err os.Error) {
		falcore.Fine("Dialing connection to %v", u.tcpaddr)
		var ctcp *net.TCPConn
		ctcp, err = net.DialTCP("tcp4", nil, u.tcpaddr)
		if ctcp != nil {
			ctcp.SetTimeout(u.Timeout)
		}
		if err != nil {
			falcore.Error("Dial Failed: %v", err)
		}
		return ctcp, err
	}
	u.transport.MaxIdleConnsPerHost = 15
	return u
}