Ejemplo n.º 1
0
func setReqVersion(req *http.Request) {
	if req.Header == nil {
		req.Header = make(map[string]string)
	}
	req.Header["Vault-Build"] = sys.Build
	req.Header["Vault-Proto"] = Version
}
Ejemplo n.º 2
0
func setReqHop(req *http.Request, h int) {
	if req.Header == nil {
		req.Header = make(map[string]string)
	}
	req.Header["Vault-Hop"] = strconv.Itoa(h)
}
Ejemplo n.º 3
0
func setOrigin(req *http.Request, id sys.Id) {
	if req.Header == nil {
		req.Header = make(map[string]string)
	}
	req.Header["Vault-Origin"] = id.Eye()
}
Ejemplo n.º 4
0
func (v *Vault0) serve(req *http.Request, my bool) (*http.Response, os.Error) {
	// We don't expect a body in requests (at this stage, there are no POSTs)
	if req.Body != nil {
		req.Body.Close()
		req.Body = nil
	}

	// Parse the URL
	tid, fpath, query, err := parseURL(req)
	if err != nil {
		return newRespBadRequest(), os.ErrorString("bad request")
	}

	// If request is at its final destination
	if tid == v.id {
		h, err := parseReqHop(req)
		if err == nil {
			v.w.AddHopsFwd(h) // Stat hop count at destination
		}
		resp, err := v.serveLocal(fpath, query)
		if err == nil {
			setRespHop(resp, 0)
		}
		return resp, err
	}

	// Stop if too many hops or hops not included
	h, err := parseReqHop(req)
	if err != nil || h > maxHops {
		v.w.IncTooManyHops()
		return newRespServiceUnavailable(), os.ErrorString("too many hops")
	}

	// Parse the HTTP header
	sid, err := parseOrigin(req)
	if err != nil {
		sid = v.id
	}
	hid := v.c.QueryQuantize(sid, tid)
	if hid == nil {
		return newRespServiceUnavailable(), os.ErrorString("no route to destination")
	}
	d := v.isHealthy()
	if d == nil {
		return newRespServiceUnavailable(), os.ErrorString("service unavailable")
	}
	cc := d.Dial(*hid, "vault0")
	if cc == nil {
		return newRespServiceUnavailable(), os.ErrorString("service unavailable")
	}
	pcc := prof.NewConn(cc)
	acc := http.NewAsyncClientConn(pcc)

	// Pre-fetch
	_, err = parseReqHop(req)
	if err != nil {
		setReqHop(req, 0)
	}
	setReqVersion(req)

	// Fetch and post-fetch
	resp, err := acc.Fetch(req)
	if err != nil {
		acc.Close()
		pcc.Close()
		return newRespServiceUnavailable(), os.ErrorString("service unavailable")
	}

	// Update hop
	setRespVersion(resp)
	h, err = parseRespHop(resp)
	if err == nil {
		setRespHop(resp, h+1)
	} else {
		setRespHop(resp, 0)
	}

	// Do we understand the response?
	if !statusCodeSupported(resp.StatusCode) {
		acc.Close()
		pcc.Close()
		return newRespUnsupported(), nil
	}

	// Set hooks for when body is fully read
	if resp.Body == nil {
		// Update traffic stats
		if my {
			v.w.IncFwdMyInTraffic(*hid, pcc.InTraffic())
			v.w.IncFwdMyOutTraffic(*hid, pcc.OutTraffic())
		} else {
			v.w.IncFwdBehalfInTraffic(*hid, pcc.InTraffic())
			v.w.IncFwdBehalfOutTraffic(*hid, pcc.OutTraffic())
		}
		v.w.RecFwdLatencyPerByte(*hid, float64(pcc.Duration())/float64(pcc.InTraffic()))

		acc.Close()
		pcc.Close()
	} else {
		resp.Body = http.NewRunOnClose(resp.Body, func() {
			// Update traffic stats
			if my {
				v.w.IncFwdMyInTraffic(*hid, pcc.InTraffic())
				v.w.IncFwdMyOutTraffic(*hid, pcc.OutTraffic())
			} else {
				v.w.IncFwdBehalfInTraffic(*hid, pcc.InTraffic())
				v.w.IncFwdBehalfOutTraffic(*hid, pcc.OutTraffic())
			}
			v.w.RecFwdLatencyPerByte(*hid, float64(pcc.Duration())/float64(pcc.InTraffic()))

			acc.Close()
			pcc.Close()
		})
	}

	return resp, nil
}