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 }
func setReqHop(req *http.Request, h int) { if req.Header == nil { req.Header = make(map[string]string) } req.Header["Vault-Hop"] = strconv.Itoa(h) }
func setOrigin(req *http.Request, id sys.Id) { if req.Header == nil { req.Header = make(map[string]string) } req.Header["Vault-Origin"] = id.Eye() }
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 }