func (v *Vault0) serveLocal(fpath, query string) (*http.Response, os.Error) { fpath = path.Clean(fpath) if len(fpath) > 0 && fpath[0] == '/' { fpath = fpath[1:] } if fpath == "" { fpath = "index.html" } full := path.Join(v.hdir, fpath) if !isFile(full) { if fpath == "index.html" { return newRespNoIndexHTML(), nil } else { return newRespNotFound(), os.ErrorString("not found") } } // Serve file if we can allocate a file descriptor in time if v.fdlim.LockOrTimeout(10e9) == nil { body, bodylen, err := http.FileToBody(full) if err != nil { if body != nil { body.Close() } v.fdlim.Unlock() return newRespServiceUnavailable(), os.ErrorString("service unavailable") } body = http.NewRunOnClose(body, func() { v.fdlim.Unlock() }) return buildRespFromBody(body, bodylen), nil } else { return newRespServiceUnavailable(), os.ErrorString("service unavailable") } panic("unreach") }
func (mon *Monitor) report(url *http.URL, every int64) { i := 0 for { // Sleep between updates if i > 0 { time.Sleep(every) } i++ // Prepare HTTP request jj, err := mon.dumper.MarshalJSON() if err != nil { continue } //printJSON(jj) repbuf, err := EncodeReport(jj, mon.key) if err != nil { continue } bodylen, body := http.BytesToBody(repbuf) req := &http.Request{ Method: "POST", URL: url, Body: body, ContentLength: int64(bodylen), Close: true, UserAgent: sys.Name + "-Client-Monitor", } // Connect conn, err := net.Dial("tcp", "", url.Host) if err != nil { if conn != nil { conn.Close() } continue } cc := http.NewClientConn(conn, nil) // Send request wch := make(chan int, 1) req.Body = http.NewRunOnClose(req.Body, func() { wch <- 1 }) err = cc.Write(req) if err != nil { cc.Close() conn.Close() } else { <-wch // wait until the request has been sent cc.Close() conn.Close() } } }
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 }
func (s *Server) serve(q *http.Query) { q.Continue() req := q.GetRequest() if req.Body != nil { req.Body.Close() } s.log(req, q.RemoteAddr()) // Path cleanup path := path.Clean(req.URL.Path) if path == "" { path = "/" } // Host analysis hostport := strings.Split(req.Host, ":", 2) if len(hostport) == 0 { q.Write(newRespBadRequest()) return } hostparts := misc.ReverseHost(strings.Split(hostport[0], ".", -1)) // http://5ttt.org, http://www.5ttt.org if len(hostparts) < 3 || hostparts[2] == "www" { if path == "/" { path = "/index.html" } if isIndex(path) { s.lk.Lock() s.stats.Views++ s.lk.Unlock() } var resp *http.Response if isIndex(path) { resp = s.replyIndex() } else { resp = s.replyStatic(path) } if isDownload(path) && resp.Body != nil { resp.Body = http.NewRunOnClose(resp.Body, func() { // TODO: This also counts incomplete downloads, but for now // it's fine. s.lk.Lock() s.stats.Downloads++ s.lk.Unlock() }) } q.Write(resp) return } // Remove 5ttt.org from host hostparts = hostparts[2:] // http://*.a.5ttt.org/* if hostparts[0] == "a" { q.Write(s.replyStatic("/tadmin.html")) // Trying to access a Tonika Admin return } // http://*.[id].5ttt.org if _, err := sys.ParseId(hostparts[0]); err == nil { q.Write(s.replyStatic("/turl.html")) // Trying to access a Tonika URL return } // Otherwise q.Write(newRespNotFound()) }