URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [http/] [httputil/] [reverseproxy.go] - Rev 747
Compare with Previous | Blame | View Log
// Copyright 2011 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// HTTP reverse proxy handlerpackage httputilimport ("io""log""net""net/http""net/url""strings""sync""time")// ReverseProxy is an HTTP Handler that takes an incoming request and// sends it to another server, proxying the response back to the// client.type ReverseProxy struct {// Director must be a function which modifies// the request into a new request to be sent// using Transport. Its response is then copied// back to the original client unmodified.Director func(*http.Request)// The transport used to perform proxy requests.// If nil, http.DefaultTransport is used.Transport http.RoundTripper// FlushInterval specifies the flush interval// to flush to the client while copying the// response body.// If zero, no periodic flushing is done.FlushInterval time.Duration}func singleJoiningSlash(a, b string) string {aslash := strings.HasSuffix(a, "/")bslash := strings.HasPrefix(b, "/")switch {case aslash && bslash:return a + b[1:]case !aslash && !bslash:return a + "/" + b}return a + b}// NewSingleHostReverseProxy returns a new ReverseProxy that rewrites// URLs to the scheme, host, and base path provided in target. If the// target's path is "/base" and the incoming request was for "/dir",// the target request will be for /base/dir.func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {targetQuery := target.RawQuerydirector := func(req *http.Request) {req.URL.Scheme = target.Schemereq.URL.Host = target.Hostreq.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)if targetQuery == "" || req.URL.RawQuery == "" {req.URL.RawQuery = targetQuery + req.URL.RawQuery} else {req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery}}return &ReverseProxy{Director: director}}func copyHeader(dst, src http.Header) {for k, vv := range src {for _, v := range vv {dst.Add(k, v)}}}func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {transport := p.Transportif transport == nil {transport = http.DefaultTransport}outreq := new(http.Request)*outreq = *req // includes shallow copies of maps, but okayp.Director(outreq)outreq.Proto = "HTTP/1.1"outreq.ProtoMajor = 1outreq.ProtoMinor = 1outreq.Close = false// Remove the connection header to the backend. We want a// persistent connection, regardless of what the client sent// to us. This is modifying the same underlying map from req// (shallow copied above) so we only copy it if necessary.if outreq.Header.Get("Connection") != "" {outreq.Header = make(http.Header)copyHeader(outreq.Header, req.Header)outreq.Header.Del("Connection")}if clientIp, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {outreq.Header.Set("X-Forwarded-For", clientIp)}res, err := transport.RoundTrip(outreq)if err != nil {log.Printf("http: proxy error: %v", err)rw.WriteHeader(http.StatusInternalServerError)return}copyHeader(rw.Header(), res.Header)rw.WriteHeader(res.StatusCode)if res.Body != nil {var dst io.Writer = rwif p.FlushInterval != 0 {if wf, ok := rw.(writeFlusher); ok {dst = &maxLatencyWriter{dst: wf, latency: p.FlushInterval}}}io.Copy(dst, res.Body)}}type writeFlusher interface {io.Writerhttp.Flusher}type maxLatencyWriter struct {dst writeFlusherlatency time.Durationlk sync.Mutex // protects init of done, as well Write + Flushdone chan bool}func (m *maxLatencyWriter) Write(p []byte) (n int, err error) {m.lk.Lock()defer m.lk.Unlock()if m.done == nil {m.done = make(chan bool)go m.flushLoop()}n, err = m.dst.Write(p)if err != nil {m.done <- true}return}func (m *maxLatencyWriter) flushLoop() {t := time.NewTicker(m.latency)defer t.Stop()for {select {case <-t.C:m.lk.Lock()m.dst.Flush()m.lk.Unlock()case <-m.done:return}}panic("unreached")}
