<commit_before>package transport

import (
	"bufio"
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync"
	"time"

	mls "github.com/micro/misc/lib/tls"
)

type buffer struct {
	io.ReadWriter
}

type httpTransport struct {
	opts Options
}

type httpTransportClient struct {
	ht       *httpTransport
	addr     string
	conn     net.Conn
	dialOpts DialOptions
	once     sync.Once

	sync.Mutex
	r    chan *http.Request
	bl   []*http.Request
	buff *bufio.Reader
}

type httpTransportSocket struct {
	ht   *httpTransport
	r    chan *http.Request
	conn net.Conn
	once sync.Once

	sync.Mutex
	buff *bufio.Reader
}

type httpTransportListener struct {
	ht       *httpTransport
	listener net.Listener
}

func listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, error) {
	// host:port || host:min-max
	parts := strings.Split(addr, ":")

	//
	if len(parts) < 2 {
		return fn(addr)
	}

	// try to extract port range
	ports := strings.Split(parts[len(parts)-1], "-")

	// single port
	if len(ports) < 2 {
		return fn(addr)
	}

	// we have a port range

	// extract min port
	min, err := strconv.Atoi(ports[0])
	if err != nil {
		return nil, errors.New("unable to extract port range")
	}

	// extract max port
	max, err := strconv.Atoi(ports[1])
	if err != nil {
		return nil, errors.New("unable to extract port range")
	}

	// set host
	host := parts[:len(parts)-1]

	// range the ports
	for port := min; port <= max; port++ {
		// try bind to host:port
		ln, err := fn(fmt.Sprintf("%s:%d", host, port))
		if err == nil {
			return ln, nil
		}

		// hit max port
		if port == max {
			return nil, err
		}
	}

	// why are we here?
	return nil, fmt.Errorf("unable to bind to %s", addr)
}

func (b *buffer) Close() error {
	return nil
}

func (h *httpTransportClient) Send(m *Message) error {
	header := make(http.Header)

	for k, v := range m.Header {
		header.Set(k, v)
	}

	reqB := bytes.NewBuffer(m.Body)
	defer reqB.Reset()
	buf := &buffer{
		reqB,
	}

	req := &http.Request{
		Method: "POST",
		URL: &url.URL{
			Scheme: "http",
			Host:   h.addr,
		},
		Header:        header,
		Body:          buf,
		ContentLength: int64(reqB.Len()),
		Host:          h.addr,
	}

	h.Lock()
	h.bl = append(h.bl, req)
	select {
	case h.r <- h.bl[0]:
		h.bl = h.bl[1:]
	default:
	}
	h.Unlock()

	// set timeout if its greater than 0
	if h.ht.opts.Timeout > time.Duration(0) {
		h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
	}

	return req.Write(h.conn)
}

func (h *httpTransportClient) Recv(m *Message) error {
	var r *http.Request
	if !h.dialOpts.Stream {
		rc, ok := <-h.r
		if !ok {
			return io.EOF
		}
		r = rc
	}

	h.Lock()
	defer h.Unlock()
	if h.buff == nil {
		return io.EOF
	}

	// set timeout if its greater than 0
	if h.ht.opts.Timeout > time.Duration(0) {
		h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
	}

	rsp, err := http.ReadResponse(h.buff, r)
	if err != nil {
		return err
	}
	defer rsp.Body.Close()

	b, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		return err
	}

	if rsp.StatusCode != 200 {
		return errors.New(rsp.Status + ": " + string(b))
	}

	mr := &Message{
		Header: make(map[string]string),
		Body:   b,
	}

	for k, v := range rsp.Header {
		if len(v) > 0 {
			mr.Header[k] = v[0]
		} else {
			mr.Header[k] = ""
		}
	}

	*m = *mr
	return nil
}

func (h *httpTransportClient) Close() error {
	err := h.conn.Close()
	h.once.Do(func() {
		h.Lock()
		h.buff.Reset(nil)
		h.buff = nil
		h.Unlock()
		close(h.r)
	})
	return err
}

func (h *httpTransportSocket) Recv(m *Message) error {
	if m == nil {
		return errors.New("message passed in is nil")
	}

	// set timeout if its greater than 0
	if h.ht.opts.Timeout > time.Duration(0) {
		h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
	}

	r, err := http.ReadRequest(h.buff)
	if err != nil {
		return err
	}

	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	r.Body.Close()

	mr := &Message{
		Header: make(map[string]string),
		Body:   b,
	}

	for k, v := range r.Header {
		if len(v) > 0 {
			mr.Header[k] = v[0]
		} else {
			mr.Header[k] = ""
		}
	}

	select {
	case h.r <- r:
	default:
	}

	*m = *mr
	return nil
}

func (h *httpTransportSocket) Send(m *Message) error {
	b := bytes.NewBuffer(m.Body)
	defer b.Reset()

	r := <-h.r

	rsp := &http.Response{
		Header:        r.Header,
		Body:          &buffer{b},
		Status:        "200 OK",
		StatusCode:    200,
		Proto:         "HTTP/1.1",
		ProtoMajor:    1,
		ProtoMinor:    1,
		ContentLength: int64(len(m.Body)),
	}

	for k, v := range m.Header {
		rsp.Header.Set(k, v)
	}

	select {
	case h.r <- r:
	default:
	}

	// set timeout if its greater than 0
	if h.ht.opts.Timeout > time.Duration(0) {
		h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
	}

	return rsp.Write(h.conn)
}

func (h *httpTransportSocket) error(m *Message) error {
	b := bytes.NewBuffer(m.Body)
	defer b.Reset()
	rsp := &http.Response{
		Header:        make(http.Header),
		Body:          &buffer{b},
		Status:        "500 Internal Server Error",
		StatusCode:    500,
		Proto:         "HTTP/1.1",
		ProtoMajor:    1,
		ProtoMinor:    1,
		ContentLength: int64(len(m.Body)),
	}

	for k, v := range m.Header {
		rsp.Header.Set(k, v)
	}

	return rsp.Write(h.conn)
}

func (h *httpTransportSocket) Close() error {
	err := h.conn.Close()
	h.once.Do(func() {
		h.Lock()
		h.buff.Reset(nil)
		h.buff = nil
		h.Unlock()
	})
	return err
}

func (h *httpTransportListener) Addr() string {
	return h.listener.Addr().String()
}

func (h *httpTransportListener) Close() error {
	return h.listener.Close()
}

func (h *httpTransportListener) Accept(fn func(Socket)) error {
	var tempDelay time.Duration

	for {
		c, err := h.listener.Accept()
		if err != nil {
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := 1 * time.Second; tempDelay > max {
					tempDelay = max
				}
				log.Printf("http: Accept error: %v; retrying in %v\n", err, tempDelay)
				time.Sleep(tempDelay)
				continue
			}
			return err
		}

		sock := &httpTransportSocket{
			ht:   h.ht,
			conn: c,
			buff: bufio.NewReader(c),
			r:    make(chan *http.Request, 1),
		}

		go func() {
			// TODO: think of a better error response strategy
			defer func() {
				if r := recover(); r != nil {
					sock.Close()
				}
			}()

			fn(sock)
		}()
	}
}

func (h *httpTransport) Dial(addr string, opts ...DialOption) (Client, error) {
	dopts := DialOptions{
		Timeout: DefaultDialTimeout,
	}

	for _, opt := range opts {
		opt(&dopts)
	}

	var conn net.Conn
	var err error

	// TODO: support dial option here rather than using internal config
	if h.opts.Secure || h.opts.TLSConfig != nil {
		config := h.opts.TLSConfig
		if config == nil {
			config = &tls.Config{
				InsecureSkipVerify: true,
			}
		}
		conn, err = tls.DialWithDialer(&net.Dialer{Timeout: dopts.Timeout}, "tcp", addr, config)
	} else {
		conn, err = net.DialTimeout("tcp", addr, dopts.Timeout)
	}

	if err != nil {
		return nil, err
	}

	return &httpTransportClient{
		ht:       h,
		addr:     addr,
		conn:     conn,
		buff:     bufio.NewReader(conn),
		dialOpts: dopts,
		r:        make(chan *http.Request, 1),
	}, nil
}

func (h *httpTransport) Listen(addr string, opts ...ListenOption) (Listener, error) {
	var options ListenOptions
	for _, o := range opts {
		o(&options)
	}

	var l net.Listener
	var err error

	// TODO: support use of listen options
	if h.opts.Secure || h.opts.TLSConfig != nil {
		config := h.opts.TLSConfig

		fn := func(addr string) (net.Listener, error) {
			if config == nil {
				hosts := []string{addr}

				// check if its a valid host:port
				if host, _, err := net.SplitHostPort(addr); err == nil {
					if len(host) == 0 {
						hosts = getIPAddrs()
					} else {
						hosts = []string{host}
					}
				}

				// generate a certificate
				cert, err := mls.Certificate(hosts...)
				if err != nil {
					return nil, err
				}
				config = &tls.Config{Certificates: []tls.Certificate{cert}}
			}
			return tls.Listen("tcp", addr, config)
		}

		l, err = listen(addr, fn)
	} else {
		fn := func(addr string) (net.Listener, error) {
			return net.Listen("tcp", addr)
		}

		l, err = listen(addr, fn)
	}

	if err != nil {
		return nil, err
	}

	return &httpTransportListener{
		ht:       h,
		listener: l,
	}, nil
}

func (h *httpTransport) String() string {
	return "http"
}

func getIPAddrs() []string {
	ifaces, err := net.Interfaces()
	if err != nil {
		return nil
	}

	var ipAddrs []string

	for _, i := range ifaces {
		addrs, err := i.Addrs()
		if err != nil {
			continue
		}

		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}

			if ip == nil {
				continue
			}

			ip = ip.To4()
			if ip == nil {
				continue
			}

			ipAddrs = append(ipAddrs, ip.String())
		}
	}

	return ipAddrs
}

func newHTTPTransport(opts ...Option) *httpTransport {
	var options Options
	for _, o := range opts {
		o(&options)
	}
	return &httpTransport{opts: options}
}
<commit_msg>Don't create new message<commit_after>package transport

import (
	"bufio"
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync"
	"time"

	mls "github.com/micro/misc/lib/tls"
)

type buffer struct {
	io.ReadWriter
}

type httpTransport struct {
	opts Options
}

type httpTransportClient struct {
	ht       *httpTransport
	addr     string
	conn     net.Conn
	dialOpts DialOptions
	once     sync.Once

	sync.Mutex
	r    chan *http.Request
	bl   []*http.Request
	buff *bufio.Reader
}

type httpTransportSocket struct {
	ht   *httpTransport
	r    chan *http.Request
	conn net.Conn
	once sync.Once

	sync.Mutex
	buff *bufio.Reader
}

type httpTransportListener struct {
	ht       *httpTransport
	listener net.Listener
}

func listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, error) {
	// host:port || host:min-max
	parts := strings.Split(addr, ":")

	//
	if len(parts) < 2 {
		return fn(addr)
	}

	// try to extract port range
	ports := strings.Split(parts[len(parts)-1], "-")

	// single port
	if len(ports) < 2 {
		return fn(addr)
	}

	// we have a port range

	// extract min port
	min, err := strconv.Atoi(ports[0])
	if err != nil {
		return nil, errors.New("unable to extract port range")
	}

	// extract max port
	max, err := strconv.Atoi(ports[1])
	if err != nil {
		return nil, errors.New("unable to extract port range")
	}

	// set host
	host := parts[:len(parts)-1]

	// range the ports
	for port := min; port <= max; port++ {
		// try bind to host:port
		ln, err := fn(fmt.Sprintf("%s:%d", host, port))
		if err == nil {
			return ln, nil
		}

		// hit max port
		if port == max {
			return nil, err
		}
	}

	// why are we here?
	return nil, fmt.Errorf("unable to bind to %s", addr)
}

func (b *buffer) Close() error {
	return nil
}

func (h *httpTransportClient) Send(m *Message) error {
	header := make(http.Header)

	for k, v := range m.Header {
		header.Set(k, v)
	}

	reqB := bytes.NewBuffer(m.Body)
	defer reqB.Reset()
	buf := &buffer{
		reqB,
	}

	req := &http.Request{
		Method: "POST",
		URL: &url.URL{
			Scheme: "http",
			Host:   h.addr,
		},
		Header:        header,
		Body:          buf,
		ContentLength: int64(reqB.Len()),
		Host:          h.addr,
	}

	h.Lock()
	h.bl = append(h.bl, req)
	select {
	case h.r <- h.bl[0]:
		h.bl = h.bl[1:]
	default:
	}
	h.Unlock()

	// set timeout if its greater than 0
	if h.ht.opts.Timeout > time.Duration(0) {
		h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
	}

	return req.Write(h.conn)
}

func (h *httpTransportClient) Recv(m *Message) error {
	if m == nil {
		return errors.New("message passed in is nil")
	}

	var r *http.Request
	if !h.dialOpts.Stream {
		rc, ok := <-h.r
		if !ok {
			return io.EOF
		}
		r = rc
	}

	h.Lock()
	defer h.Unlock()
	if h.buff == nil {
		return io.EOF
	}

	// set timeout if its greater than 0
	if h.ht.opts.Timeout > time.Duration(0) {
		h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
	}

	rsp, err := http.ReadResponse(h.buff, r)
	if err != nil {
		return err
	}
	defer rsp.Body.Close()

	b, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		return err
	}

	if rsp.StatusCode != 200 {
		return errors.New(rsp.Status + ": " + string(b))
	}

	m.Body = b

	if m.Header == nil {
		m.Header = make(map[string]string)
	}

	for k, v := range rsp.Header {
		if len(v) > 0 {
			m.Header[k] = v[0]
		} else {
			m.Header[k] = ""
		}
	}

	return nil
}

func (h *httpTransportClient) Close() error {
	err := h.conn.Close()
	h.once.Do(func() {
		h.Lock()
		h.buff.Reset(nil)
		h.buff = nil
		h.Unlock()
		close(h.r)
	})
	return err
}

func (h *httpTransportSocket) Recv(m *Message) error {
	if m == nil {
		return errors.New("message passed in is nil")
	}

	// set timeout if its greater than 0
	if h.ht.opts.Timeout > time.Duration(0) {
		h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
	}

	r, err := http.ReadRequest(h.buff)
	if err != nil {
		return err
	}

	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	r.Body.Close()
	m.Body = b

	if m.Header == nil {
		m.Header = make(map[string]string)
	}

	for k, v := range r.Header {
		if len(v) > 0 {
			m.Header[k] = v[0]
		} else {
			m.Header[k] = ""
		}
	}

	select {
	case h.r <- r:
	default:
	}

	return nil
}

func (h *httpTransportSocket) Send(m *Message) error {
	b := bytes.NewBuffer(m.Body)
	defer b.Reset()

	r := <-h.r

	rsp := &http.Response{
		Header:        r.Header,
		Body:          &buffer{b},
		Status:        "200 OK",
		StatusCode:    200,
		Proto:         "HTTP/1.1",
		ProtoMajor:    1,
		ProtoMinor:    1,
		ContentLength: int64(len(m.Body)),
	}

	for k, v := range m.Header {
		rsp.Header.Set(k, v)
	}

	select {
	case h.r <- r:
	default:
	}

	// set timeout if its greater than 0
	if h.ht.opts.Timeout > time.Duration(0) {
		h.conn.SetDeadline(time.Now().Add(h.ht.opts.Timeout))
	}

	return rsp.Write(h.conn)
}

func (h *httpTransportSocket) error(m *Message) error {
	b := bytes.NewBuffer(m.Body)
	defer b.Reset()
	rsp := &http.Response{
		Header:        make(http.Header),
		Body:          &buffer{b},
		Status:        "500 Internal Server Error",
		StatusCode:    500,
		Proto:         "HTTP/1.1",
		ProtoMajor:    1,
		ProtoMinor:    1,
		ContentLength: int64(len(m.Body)),
	}

	for k, v := range m.Header {
		rsp.Header.Set(k, v)
	}

	return rsp.Write(h.conn)
}

func (h *httpTransportSocket) Close() error {
	err := h.conn.Close()
	h.once.Do(func() {
		h.Lock()
		h.buff.Reset(nil)
		h.buff = nil
		h.Unlock()
	})
	return err
}

func (h *httpTransportListener) Addr() string {
	return h.listener.Addr().String()
}

func (h *httpTransportListener) Close() error {
	return h.listener.Close()
}

func (h *httpTransportListener) Accept(fn func(Socket)) error {
	var tempDelay time.Duration

	for {
		c, err := h.listener.Accept()
		if err != nil {
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := 1 * time.Second; tempDelay > max {
					tempDelay = max
				}
				log.Printf("http: Accept error: %v; retrying in %v\n", err, tempDelay)
				time.Sleep(tempDelay)
				continue
			}
			return err
		}

		sock := &httpTransportSocket{
			ht:   h.ht,
			conn: c,
			buff: bufio.NewReader(c),
			r:    make(chan *http.Request, 1),
		}

		go func() {
			// TODO: think of a better error response strategy
			defer func() {
				if r := recover(); r != nil {
					sock.Close()
				}
			}()

			fn(sock)
		}()
	}
}

func (h *httpTransport) Dial(addr string, opts ...DialOption) (Client, error) {
	dopts := DialOptions{
		Timeout: DefaultDialTimeout,
	}

	for _, opt := range opts {
		opt(&dopts)
	}

	var conn net.Conn
	var err error

	// TODO: support dial option here rather than using internal config
	if h.opts.Secure || h.opts.TLSConfig != nil {
		config := h.opts.TLSConfig
		if config == nil {
			config = &tls.Config{
				InsecureSkipVerify: true,
			}
		}
		conn, err = tls.DialWithDialer(&net.Dialer{Timeout: dopts.Timeout}, "tcp", addr, config)
	} else {
		conn, err = net.DialTimeout("tcp", addr, dopts.Timeout)
	}

	if err != nil {
		return nil, err
	}

	return &httpTransportClient{
		ht:       h,
		addr:     addr,
		conn:     conn,
		buff:     bufio.NewReader(conn),
		dialOpts: dopts,
		r:        make(chan *http.Request, 1),
	}, nil
}

func (h *httpTransport) Listen(addr string, opts ...ListenOption) (Listener, error) {
	var options ListenOptions
	for _, o := range opts {
		o(&options)
	}

	var l net.Listener
	var err error

	// TODO: support use of listen options
	if h.opts.Secure || h.opts.TLSConfig != nil {
		config := h.opts.TLSConfig

		fn := func(addr string) (net.Listener, error) {
			if config == nil {
				hosts := []string{addr}

				// check if its a valid host:port
				if host, _, err := net.SplitHostPort(addr); err == nil {
					if len(host) == 0 {
						hosts = getIPAddrs()
					} else {
						hosts = []string{host}
					}
				}

				// generate a certificate
				cert, err := mls.Certificate(hosts...)
				if err != nil {
					return nil, err
				}
				config = &tls.Config{Certificates: []tls.Certificate{cert}}
			}
			return tls.Listen("tcp", addr, config)
		}

		l, err = listen(addr, fn)
	} else {
		fn := func(addr string) (net.Listener, error) {
			return net.Listen("tcp", addr)
		}

		l, err = listen(addr, fn)
	}

	if err != nil {
		return nil, err
	}

	return &httpTransportListener{
		ht:       h,
		listener: l,
	}, nil
}

func (h *httpTransport) String() string {
	return "http"
}

func getIPAddrs() []string {
	ifaces, err := net.Interfaces()
	if err != nil {
		return nil
	}

	var ipAddrs []string

	for _, i := range ifaces {
		addrs, err := i.Addrs()
		if err != nil {
			continue
		}

		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}

			if ip == nil {
				continue
			}

			ip = ip.To4()
			if ip == nil {
				continue
			}

			ipAddrs = append(ipAddrs, ip.String())
		}
	}

	return ipAddrs
}

func newHTTPTransport(opts ...Option) *httpTransport {
	var options Options
	for _, o := range opts {
		o(&options)
	}
	return &httpTransport{opts: options}
}
<|endoftext|>


<commit_before>package registry

import (
	"net/http"

	"github.com/cozy/cozy-stack/model/permission"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/registry"
	"github.com/cozy/cozy-stack/web/middlewares"
	"github.com/cozy/echo"
	"github.com/cozy/echo/middleware"
)

type authType int

const (
	authed authType = iota
	perms
)

func proxyReq(auth authType, clientPermanentCache bool, proxyCacheControl registry.CacheControl) echo.HandlerFunc {
	return func(c echo.Context) error {
		i := middlewares.GetInstance(c)
		switch auth {
		case authed:
			if !middlewares.IsLoggedIn(c) || !middlewares.HasWebAppToken(c) {
				if err := middlewares.AllowWholeType(c, permission.GET, consts.Apps); err != nil {
					return echo.NewHTTPError(http.StatusForbidden)
				}
			}
		case perms:
			pdoc, err := middlewares.GetPermission(c)
			if err != nil || pdoc.Type != permission.TypeWebapp {
				return echo.NewHTTPError(http.StatusForbidden)
			}
		default:
			panic("unknown authType")
		}
		req := c.Request()
		proxyResp, err := registry.Proxy(req, i.Registries(), proxyCacheControl)
		if err != nil {
			return err
		}
		defer proxyResp.Body.Close()
		if clientPermanentCache {
			c.Response().Header().Set("Cache-Control", "max-age=31536000, immutable")
		}
		contentType := proxyResp.Header.Get("content-type")
		return c.Stream(proxyResp.StatusCode, contentType, proxyResp.Body)
	}
}

func proxyListReq(c echo.Context) error {
	i := middlewares.GetInstance(c)
	if !middlewares.HasWebAppToken(c) {
		return echo.NewHTTPError(http.StatusForbidden)
	}
	req := c.Request()
	list, err := registry.ProxyList(req, i.Registries())
	if err != nil {
		return err
	}
	return c.JSON(http.StatusOK, list)
}

// Routes sets the routing for the registry
func Routes(router *echo.Group) {
	gzip := middleware.Gzip()
	router.GET("", proxyListReq, gzip)
	router.GET("/", proxyListReq, gzip)
	router.GET("/:app", proxyReq(perms, false, registry.WithCache))
	router.GET("/:app/icon", proxyReq(authed, false, registry.NoCache))
	router.GET("/:app/partnership_icon", proxyReq(authed, false, registry.NoCache))
	router.GET("/:app/screenshots/*", proxyReq(authed, false, registry.NoCache))
	router.GET("/:app/:version/icon", proxyReq(authed, true, registry.NoCache))
	router.GET("/:app/:version/partnership_icon", proxyReq(authed, true, registry.NoCache))
	router.GET("/:app/:version/screenshots/*", proxyReq(authed, true, registry.NoCache))
	router.GET("/:app/:version", proxyReq(perms, true, registry.WithCache))
	router.GET("/:app/:channel/latest", proxyReq(perms, false, registry.WithCache))
}
<commit_msg>Allow cozy-store to preload app icons from registry<commit_after>package registry

import (
	"net/http"

	"github.com/cozy/cozy-stack/model/permission"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/registry"
	"github.com/cozy/cozy-stack/web/middlewares"
	"github.com/cozy/echo"
	"github.com/cozy/echo/middleware"
)

type authType int

const (
	authed authType = iota
	perms
)

func proxyReq(auth authType, clientPermanentCache bool, proxyCacheControl registry.CacheControl) echo.HandlerFunc {
	return func(c echo.Context) error {
		i := middlewares.GetInstance(c)
		switch auth {
		case authed:
			if !middlewares.IsLoggedIn(c) {
				if err := middlewares.AllowWholeType(c, permission.GET, consts.Apps); err != nil {
					return echo.NewHTTPError(http.StatusForbidden)
				}
			}
		case perms:
			pdoc, err := middlewares.GetPermission(c)
			if err != nil || pdoc.Type != permission.TypeWebapp {
				return echo.NewHTTPError(http.StatusForbidden)
			}
		default:
			panic("unknown authType")
		}
		req := c.Request()
		proxyResp, err := registry.Proxy(req, i.Registries(), proxyCacheControl)
		if err != nil {
			return err
		}
		defer proxyResp.Body.Close()
		if clientPermanentCache {
			c.Response().Header().Set("Cache-Control", "max-age=31536000, immutable")
		}
		contentType := proxyResp.Header.Get("content-type")
		return c.Stream(proxyResp.StatusCode, contentType, proxyResp.Body)
	}
}

func proxyListReq(c echo.Context) error {
	i := middlewares.GetInstance(c)
	if !middlewares.HasWebAppToken(c) {
		return echo.NewHTTPError(http.StatusForbidden)
	}
	req := c.Request()
	list, err := registry.ProxyList(req, i.Registries())
	if err != nil {
		return err
	}
	return c.JSON(http.StatusOK, list)
}

// Routes sets the routing for the registry
func Routes(router *echo.Group) {
	gzip := middleware.Gzip()
	router.GET("", proxyListReq, gzip)
	router.GET("/", proxyListReq, gzip)
	router.GET("/:app", proxyReq(perms, false, registry.WithCache))
	router.GET("/:app/icon", proxyReq(authed, false, registry.NoCache))
	router.GET("/:app/partnership_icon", proxyReq(authed, false, registry.NoCache))
	router.GET("/:app/screenshots/*", proxyReq(authed, false, registry.NoCache))
	router.GET("/:app/:version/icon", proxyReq(authed, true, registry.NoCache))
	router.GET("/:app/:version/partnership_icon", proxyReq(authed, true, registry.NoCache))
	router.GET("/:app/:version/screenshots/*", proxyReq(authed, true, registry.NoCache))
	router.GET("/:app/:version", proxyReq(perms, true, registry.WithCache))
	router.GET("/:app/:channel/latest", proxyReq(perms, false, registry.WithCache))
}
<|endoftext|>


<commit_before>// Copyright 2014 Volker Dobler.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ht

import (
	"fmt"
	"net/http"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

// Repeat returns count copies of test with variables replaced based
// on vars. The keys of vars are the variable names. The values of a
// variable v are choosen from vars[v] by cycling through the list:
// In the n'th repetition is vars[v][n%N] with N=len(vars[v])).
func Repeat(test *Test, count int, vars map[string][]string) ([]*Test, error) {
	reps := make([]*Test, count)
	for r := 0; r < count; r++ {
		curVars := make(map[string]string)
		for k, v := range vars {
			curVars[k] = v[r%len(v)]
		}
		replacer, err := newReplacer(curVars)
		if err != nil {
			return nil, err
		}

		reps[r] = test.substituteVariables(replacer)
		for k, v := range curVars {
			reps[r].Description += fmt.Sprintf("\nVar %s=%q", k, v)
		}
	}
	return reps, nil
}

// lcm computest the least common multiple of m and n.
func lcm(m, n int) int {
	a, b := m, n
	for a != b {
		if a < b {
			a += m
		} else {
			b += n
		}
	}
	return a
}

// lcmOf computes the least common multiple of the length of all valuesin vars.
func lcmOf(vars map[string][]string) int {
	n := 0
	for _, v := range vars {
		if n == 0 {
			n = len(v)
		} else {
			n = lcm(n, len(v))
		}
	}
	return n
}

// substituteVariables returns a copy of t with replacer applied.
func (t *Test) substituteVariables(repl replacer) *Test {
	// Apply to name, description, URL and body.
	c := &Test{
		Name:        repl.str.Replace(t.Name),
		Description: repl.str.Replace(t.Description),
		Request: Request{
			Method:          repl.str.Replace(t.Request.Method),
			URL:             repl.str.Replace(t.Request.URL),
			ParamsAs:        repl.str.Replace(t.Request.ParamsAs),
			Body:            repl.str.Replace(t.Request.Body),
			FollowRedirects: t.Request.FollowRedirects,
		},
		Poll:        t.Poll,
		Timeout:     t.Timeout,
		Verbosity:   t.Verbosity,
		PreSleep:    t.PreSleep,
		InterSleep:  t.InterSleep,
		PostSleep:   t.PostSleep,
		Jar:         t.Jar,
		VarEx:       t.VarEx,
		Criticality: t.Criticality,
	}

	// Apply to request parameters.
	c.Request.Params = make(URLValues)
	for param, vals := range t.Request.Params {
		rv := make([]string, len(vals))
		for i, v := range vals {
			rv[i] = repl.str.Replace(v)
		}
		c.Request.Params[param] = rv
	}

	// Apply to http header.
	c.Request.Header = make(http.Header)
	for h, vals := range t.Request.Header {
		rv := make([]string, len(vals))
		for i, v := range vals {
			rv[i] = repl.str.Replace(v)
		}
		c.Request.Header[h] = rv
	}

	// Apply to cookie values.
	for _, cookie := range t.Request.Cookies {
		rc := Cookie{Name: cookie.Name, Value: repl.str.Replace(cookie.Value)}
		c.Request.Cookies = append(c.Request.Cookies, rc)
	}

	// Apply to checks.
	c.Checks = make([]Check, len(t.Checks))
	for i := range t.Checks {
		c.Checks[i] = SubstituteVariables(t.Checks[i], repl.str, repl.fn)
	}

	return c
}

// ----------------------------------------------------------------------------
// Variable substitutions

// addSpecialVariables adds all special variables of the forms
//     {{NOW ...}}  and
//     {{RANDOM ...}}
// in s to the map m.
// TODO: replace regexp matching with fasterand simpler code.
func addSpecialVariables(s string, m map[string]struct{}) {
	for i := strings.Index(s, "{{"); i > -1; i = strings.Index(s, "{{") {
		s = s[i:]
		if !startsWithSpecialVar(s) {
			s = s[1:]
			continue
		}
		j := strings.Index(s, "}}")
		if j == -1 {
			return // Last variable not closed, so no need to look further.
		}
		k := s[2:j]
		m[k] = struct{}{}
		s = s[j+2:]
	}
}

func startsWithSpecialVar(s string) bool {
	for _, prefix := range []string{"{{NOW", "{{RANDOM"} {
		if strings.HasPrefix(s, prefix) {
			if len(s) < 7 || isNormalVarnameChar(s[len(prefix)]) {
				return false
			}
			return true
		}
	}
	return false
}

func isNormalVarnameChar(b byte) bool {
	return (b >= '0' && b <= '9') || (b >= 'a' && b <= 'z') ||
		(b >= 'A' && b <= 'Z') || b == '_'
}

// findSpecialVariables return all occurences of special variables
// as defined in addSpecialVariables. The enclosing {{ and }} are not
// part of the variable name. The resulting list is sorted to have
// a fixed order for a reproducable asignment to random variables.
func (t *Test) findSpecialVariables() []string {
	v := map[string]struct{}{}

	addSpecialVariables(t.Name, v)
	addSpecialVariables(t.Description, v)
	addSpecialVariables(t.Request.URL, v)
	addSpecialVariables(t.Request.Body, v)
	for _, pp := range t.Request.Params {
		for _, p := range pp {
			addSpecialVariables(p, v)
		}
	}
	for _, hh := range t.Request.Header {
		for _, h := range hh {
			addSpecialVariables(h, v)
		}
	}
	for _, cookie := range t.Request.Cookies {
		addSpecialVariables(cookie.Value, v)
	}
	for _, c := range t.Checks {
		findSpecialVarsInCheck(c, v)
	}

	names := make([]string, len(v))
	i := 0
	for k := range v {
		names[i] = k
		i++
	}
	sort.Strings(names)

	return names
}

func findSpecialVarsInCheck(check Check, m map[string]struct{}) {
	v := reflect.ValueOf(check)
	findSpecialVarsInValue(v, m)
}

func findSpecialVarsInValue(v reflect.Value, m map[string]struct{}) {
	switch v.Kind() {
	case reflect.String:
		addSpecialVariables(v.String(), m)
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			findSpecialVarsInValue(v.Field(i), m)
		}
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			findSpecialVarsInValue(v.Index(i), m)
		}
	case reflect.Map:
		for _, key := range v.MapKeys() {
			findSpecialVarsInValue(v.MapIndex(key), m)
		}
	case reflect.Ptr:
		v = v.Elem()
		if !v.IsValid() {
			return
		}
		findSpecialVarsInValue(v, m)
	case reflect.Interface:
		v = v.Elem()
		findSpecialVarsInValue(v, m)
	}
}

// specialVariables produces values for all names of special variables.
func specialVariables(now time.Time, names []string) (map[string]string, error) {
	vars := make(map[string]string)
	for _, k := range names {
		if strings.HasPrefix(k, "NOW") {
			err := setNowVariable(vars, now, k)
			if err != nil {
				return vars, err
			}
		} else if strings.HasPrefix(k, "RANDOM") {
			err := setRandomVariable(vars, k)
			if err != nil {
				return vars, err
			}
		} else {
			return vars, fmt.Errorf("ht: unknown special variable %q", k)
		}
	}
	return vars, nil
}

var nowTimeRe = regexp.MustCompile(`NOW *([+-] *[1-9][0-9]*[smhd])? *(\| *"(.*)")?`)

// interprete k of the form {{NOW ...}} and set vars[k] to that vlaue.
func setNowVariable(vars map[string]string, now time.Time, k string) error {
	m := nowTimeRe.FindAllStringSubmatch(k, 1)
	if m == nil {
		panic("Unmatchable " + k)
	}
	if _, ok := vars[k]; ok {
		return nil // We already processed this variable.
	}
	var off time.Duration
	delta := m[0][1]
	if delta != "" {
		num := strings.TrimLeft(delta[1:len(delta)-1], " ")
		n, err := strconv.Atoi(num)
		if err != nil {
			return err
		}
		if delta[0] == '-' {
			n *= -1
		}
		switch delta[len(delta)-1] {
		case 's':
			n *= 1
		case 'm':
			n *= 60
		case 'h':
			n *= 60 * 60
		case 'd':
			n *= 24 * 26 * 60
		default:
			return fmt.Errorf("ht: bad now-variable delta unit %q", delta[len(delta)-1])
		}
		off = time.Duration(n) * time.Second
	}
	format := time.RFC1123
	if m[0][3] != "" {
		format = m[0][3]
	}
	formatedTime := now.Add(off).Format(format)
	vars[k] = formatedTime
	return nil
}

// mergeVariables merges all variables found in the various vars.
func mergeVariables(vars ...map[string]string) map[string]string {
	result := make(map[string]string)
	for _, e := range vars {
		for k, v := range e {
			result[k] = v
		}
	}
	return result
}

// replacer determines a set of string and integer replacements
// for the variable substitutions.
type replacer struct {
	str *strings.Replacer
	fn  map[int64]int64
}

// newReplacer produces a replacer to perform substitution of the
// given variables with their values. A key of the form "#123" (i.e. hash
// followed by literal decimal integer) is treated as an integer substitution.
// Other keys are treated as string variables which subsitutes "{{k}}" with
// vars[k] for a key k. Maybe just have a look at the code.
func newReplacer(vars map[string]string) (replacer, error) {
	oldnew := []string{}
	fn := make(map[int64]int64)
	for k, v := range vars {
		if strings.HasPrefix(k, "#") {
			// An integer substitution
			o, err := strconv.ParseInt(k[1:], 10, 64)
			if err != nil {
				return replacer{}, err
			}
			n, err := strconv.ParseInt(v, 10, 64)
			if err != nil {
				return replacer{}, err
			}
			fn[o] = n
		} else {
			// A string substitution.
			oldnew = append(oldnew, "{{"+k+"}}") // TODO: make configurable ??
			oldnew = append(oldnew, v)
		}
	}

	return replacer{
		str: strings.NewReplacer(oldnew...),
		fn:  fn,
	}, nil
}
<commit_msg>ht: remove obsolete TODO<commit_after>// Copyright 2014 Volker Dobler.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ht

import (
	"fmt"
	"net/http"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

// Repeat returns count copies of test with variables replaced based
// on vars. The keys of vars are the variable names. The values of a
// variable v are choosen from vars[v] by cycling through the list:
// In the n'th repetition is vars[v][n%N] with N=len(vars[v])).
func Repeat(test *Test, count int, vars map[string][]string) ([]*Test, error) {
	reps := make([]*Test, count)
	for r := 0; r < count; r++ {
		curVars := make(map[string]string)
		for k, v := range vars {
			curVars[k] = v[r%len(v)]
		}
		replacer, err := newReplacer(curVars)
		if err != nil {
			return nil, err
		}

		reps[r] = test.substituteVariables(replacer)
		for k, v := range curVars {
			reps[r].Description += fmt.Sprintf("\nVar %s=%q", k, v)
		}
	}
	return reps, nil
}

// lcm computest the least common multiple of m and n.
func lcm(m, n int) int {
	a, b := m, n
	for a != b {
		if a < b {
			a += m
		} else {
			b += n
		}
	}
	return a
}

// lcmOf computes the least common multiple of the length of all valuesin vars.
func lcmOf(vars map[string][]string) int {
	n := 0
	for _, v := range vars {
		if n == 0 {
			n = len(v)
		} else {
			n = lcm(n, len(v))
		}
	}
	return n
}

// substituteVariables returns a copy of t with replacer applied.
func (t *Test) substituteVariables(repl replacer) *Test {
	// Apply to name, description, URL and body.
	c := &Test{
		Name:        repl.str.Replace(t.Name),
		Description: repl.str.Replace(t.Description),
		Request: Request{
			Method:          repl.str.Replace(t.Request.Method),
			URL:             repl.str.Replace(t.Request.URL),
			ParamsAs:        repl.str.Replace(t.Request.ParamsAs),
			Body:            repl.str.Replace(t.Request.Body),
			FollowRedirects: t.Request.FollowRedirects,
		},
		Poll:        t.Poll,
		Timeout:     t.Timeout,
		Verbosity:   t.Verbosity,
		PreSleep:    t.PreSleep,
		InterSleep:  t.InterSleep,
		PostSleep:   t.PostSleep,
		Jar:         t.Jar,
		VarEx:       t.VarEx,
		Criticality: t.Criticality,
	}

	// Apply to request parameters.
	c.Request.Params = make(URLValues)
	for param, vals := range t.Request.Params {
		rv := make([]string, len(vals))
		for i, v := range vals {
			rv[i] = repl.str.Replace(v)
		}
		c.Request.Params[param] = rv
	}

	// Apply to http header.
	c.Request.Header = make(http.Header)
	for h, vals := range t.Request.Header {
		rv := make([]string, len(vals))
		for i, v := range vals {
			rv[i] = repl.str.Replace(v)
		}
		c.Request.Header[h] = rv
	}

	// Apply to cookie values.
	for _, cookie := range t.Request.Cookies {
		rc := Cookie{Name: cookie.Name, Value: repl.str.Replace(cookie.Value)}
		c.Request.Cookies = append(c.Request.Cookies, rc)
	}

	// Apply to checks.
	c.Checks = make([]Check, len(t.Checks))
	for i := range t.Checks {
		c.Checks[i] = SubstituteVariables(t.Checks[i], repl.str, repl.fn)
	}

	return c
}

// ----------------------------------------------------------------------------
// Variable substitutions

// addSpecialVariables adds all special variables of the forms
//     {{NOW ...}}  and
//     {{RANDOM ...}}
// in s to the map m.
func addSpecialVariables(s string, m map[string]struct{}) {
	for i := strings.Index(s, "{{"); i > -1; i = strings.Index(s, "{{") {
		s = s[i:]
		if !startsWithSpecialVar(s) {
			s = s[1:]
			continue
		}
		j := strings.Index(s, "}}")
		if j == -1 {
			return // Last variable not closed, so no need to look further.
		}
		k := s[2:j]
		m[k] = struct{}{}
		s = s[j+2:]
	}
}

func startsWithSpecialVar(s string) bool {
	for _, prefix := range []string{"{{NOW", "{{RANDOM"} {
		if strings.HasPrefix(s, prefix) {
			if len(s) < 7 || isNormalVarnameChar(s[len(prefix)]) {
				return false
			}
			return true
		}
	}
	return false
}

func isNormalVarnameChar(b byte) bool {
	return (b >= '0' && b <= '9') || (b >= 'a' && b <= 'z') ||
		(b >= 'A' && b <= 'Z') || b == '_'
}

// findSpecialVariables return all occurences of special variables
// as defined in addSpecialVariables. The enclosing {{ and }} are not
// part of the variable name. The resulting list is sorted to have
// a fixed order for a reproducable asignment to random variables.
func (t *Test) findSpecialVariables() []string {
	v := map[string]struct{}{}

	addSpecialVariables(t.Name, v)
	addSpecialVariables(t.Description, v)
	addSpecialVariables(t.Request.URL, v)
	addSpecialVariables(t.Request.Body, v)
	for _, pp := range t.Request.Params {
		for _, p := range pp {
			addSpecialVariables(p, v)
		}
	}
	for _, hh := range t.Request.Header {
		for _, h := range hh {
			addSpecialVariables(h, v)
		}
	}
	for _, cookie := range t.Request.Cookies {
		addSpecialVariables(cookie.Value, v)
	}
	for _, c := range t.Checks {
		findSpecialVarsInCheck(c, v)
	}

	names := make([]string, len(v))
	i := 0
	for k := range v {
		names[i] = k
		i++
	}
	sort.Strings(names)

	return names
}

func findSpecialVarsInCheck(check Check, m map[string]struct{}) {
	v := reflect.ValueOf(check)
	findSpecialVarsInValue(v, m)
}

func findSpecialVarsInValue(v reflect.Value, m map[string]struct{}) {
	switch v.Kind() {
	case reflect.String:
		addSpecialVariables(v.String(), m)
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			findSpecialVarsInValue(v.Field(i), m)
		}
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			findSpecialVarsInValue(v.Index(i), m)
		}
	case reflect.Map:
		for _, key := range v.MapKeys() {
			findSpecialVarsInValue(v.MapIndex(key), m)
		}
	case reflect.Ptr:
		v = v.Elem()
		if !v.IsValid() {
			return
		}
		findSpecialVarsInValue(v, m)
	case reflect.Interface:
		v = v.Elem()
		findSpecialVarsInValue(v, m)
	}
}

// specialVariables produces values for all names of special variables.
func specialVariables(now time.Time, names []string) (map[string]string, error) {
	vars := make(map[string]string)
	for _, k := range names {
		if strings.HasPrefix(k, "NOW") {
			err := setNowVariable(vars, now, k)
			if err != nil {
				return vars, err
			}
		} else if strings.HasPrefix(k, "RANDOM") {
			err := setRandomVariable(vars, k)
			if err != nil {
				return vars, err
			}
		} else {
			return vars, fmt.Errorf("ht: unknown special variable %q", k)
		}
	}
	return vars, nil
}

var nowTimeRe = regexp.MustCompile(`NOW *([+-] *[1-9][0-9]*[smhd])? *(\| *"(.*)")?`)

// interprete k of the form {{NOW ...}} and set vars[k] to that vlaue.
func setNowVariable(vars map[string]string, now time.Time, k string) error {
	m := nowTimeRe.FindAllStringSubmatch(k, 1)
	if m == nil {
		panic("Unmatchable " + k)
	}
	if _, ok := vars[k]; ok {
		return nil // We already processed this variable.
	}
	var off time.Duration
	delta := m[0][1]
	if delta != "" {
		num := strings.TrimLeft(delta[1:len(delta)-1], " ")
		n, err := strconv.Atoi(num)
		if err != nil {
			return err
		}
		if delta[0] == '-' {
			n *= -1
		}
		switch delta[len(delta)-1] {
		case 's':
			n *= 1
		case 'm':
			n *= 60
		case 'h':
			n *= 60 * 60
		case 'd':
			n *= 24 * 26 * 60
		default:
			return fmt.Errorf("ht: bad now-variable delta unit %q", delta[len(delta)-1])
		}
		off = time.Duration(n) * time.Second
	}
	format := time.RFC1123
	if m[0][3] != "" {
		format = m[0][3]
	}
	formatedTime := now.Add(off).Format(format)
	vars[k] = formatedTime
	return nil
}

// mergeVariables merges all variables found in the various vars.
func mergeVariables(vars ...map[string]string) map[string]string {
	result := make(map[string]string)
	for _, e := range vars {
		for k, v := range e {
			result[k] = v
		}
	}
	return result
}

// replacer determines a set of string and integer replacements
// for the variable substitutions.
type replacer struct {
	str *strings.Replacer
	fn  map[int64]int64
}

// newReplacer produces a replacer to perform substitution of the
// given variables with their values. A key of the form "#123" (i.e. hash
// followed by literal decimal integer) is treated as an integer substitution.
// Other keys are treated as string variables which subsitutes "{{k}}" with
// vars[k] for a key k. Maybe just have a look at the code.
func newReplacer(vars map[string]string) (replacer, error) {
	oldnew := []string{}
	fn := make(map[int64]int64)
	for k, v := range vars {
		if strings.HasPrefix(k, "#") {
			// An integer substitution
			o, err := strconv.ParseInt(k[1:], 10, 64)
			if err != nil {
				return replacer{}, err
			}
			n, err := strconv.ParseInt(v, 10, 64)
			if err != nil {
				return replacer{}, err
			}
			fn[o] = n
		} else {
			// A string substitution.
			oldnew = append(oldnew, "{{"+k+"}}") // TODO: make configurable ??
			oldnew = append(oldnew, v)
		}
	}

	return replacer{
		str: strings.NewReplacer(oldnew...),
		fn:  fn,
	}, nil
}
<|endoftext|>


<commit_before>package libtalek

import (
	"errors"
	"sync"
	"sync/atomic"
	"time"

	"github.com/privacylab/talek/common"
	"github.com/privacylab/talek/drbg"
)

// Client represents a connection to the Talek system. Typically created with
// NewClient, the object manages requests, both reads an writes.
type Client struct {
	log    *common.Logger
	name   string
	config atomic.Value //ClientConfig
	dead   int32
	rand   *drbg.HashDrbg
	leader common.LeaderInterface

	subscriptions     []Subscription
	pendingWrites     chan *common.WriteArgs
	pendingReads      chan request
	subscriptionMutex sync.Mutex

	lastSeqNo uint64
}

type request struct {
	*common.ReadArgs
	*Subscription
}

// NewClient creates a Talek client for reading and writing metadata-protected messages.
func NewClient(name string, config ClientConfig, leader common.LeaderInterface) *Client {
	c := &Client{}
	c.log = common.NewLogger(name)
	c.name = name
	c.config.Store(config)
	c.leader = leader

	rand, err := drbg.NewHashDrbg(nil)
	if err != nil {
		c.log.Error.Fatalf("Error creating Hashdrbg: %v\n", err)
		return nil
	}
	c.rand = rand

	//todo: should channel capacity be smarter?
	c.pendingReads = make(chan request, 5)
	c.pendingWrites = make(chan *common.WriteArgs, 5)

	go c.readPeriodic()
	go c.writePeriodic()

	c.log.Info.Println("NewClient: starting new client - " + name)
	return c
}

/** PUBLIC METHODS (threadsafe) **/

func (c *Client) SetConfig(config ClientConfig) {
	c.config.Store(config)
}

func (c *Client) Kill() {
	atomic.StoreInt32(&c.dead, 1)
}

func (c *Client) Ping() bool {
	var reply common.PingReply
	err := c.leader.Ping(&common.PingArgs{Msg: "PING"}, &reply)
	if err == nil && reply.Err == "" {
		c.log.Info.Printf("Ping success\n")
		return true
	}
	c.log.Warn.Printf("Ping fail: err=%v, reply=%v\n", err, reply)
	return false
}

// MaxLength returns the maximum allowed message the client can Publish.
// TODO: support messages spanning multiple data items.
func (c *Client) MaxLength() int {
	config := c.config.Load().(ClientConfig)
	return config.DataSize
}

// Publish a new message to the end of a topic.
func (c *Client) Publish(handle *Topic, data []byte) error {
	config := c.config.Load().(ClientConfig)

	if len(data) > config.DataSize-PublishingOverhead {
		return errors.New("message too long")
	} else if len(data) < config.DataSize-PublishingOverhead {
		allocation := make([]byte, config.DataSize-PublishingOverhead)
		copy(allocation[:], data)
		data = allocation
	}

	writeArgs, err := handle.GeneratePublish(config.CommonConfig, data)
	c.log.Info.Printf("Wrote %v(%d) to %d,%d.", writeArgs.Data[0:4], len(writeArgs.Data), writeArgs.Bucket1, writeArgs.Bucket2)
	if err != nil {
		return err
	}

	c.pendingWrites <- writeArgs
	return nil
}

// Poll Subscribes to updates on a given log Subscription.
// When done reading message,s the the channel can be closed via the Done
// method.
func (c *Client) Poll(handle *Subscription) chan []byte {
	// Check if already subscribed.
	c.subscriptionMutex.Lock()
	for x := range c.subscriptions {
		if &c.subscriptions[x] == handle {
			c.subscriptionMutex.Unlock()
			return nil
		}
	}
	c.subscriptions = append(c.subscriptions, *handle)
	c.subscriptionMutex.Unlock()

	return handle.Updates
}

// Done unsubscribes a Subscription from being Polled for new items.
func (c *Client) Done(handle *Subscription) bool {
	c.subscriptionMutex.Lock()
	for i := 0; i < len(c.subscriptions); i++ {
		if &c.subscriptions[i] == handle {
			c.subscriptions[i] = c.subscriptions[len(c.subscriptions)-1]
			c.subscriptions = c.subscriptions[:len(c.subscriptions)-1]
			c.subscriptionMutex.Unlock()
			return true
		}
	}
	c.subscriptionMutex.Unlock()
	return false
}

/** Private methods **/
func (c *Client) writePeriodic() {
	var req *common.WriteArgs

	for atomic.LoadInt32(&c.dead) == 0 {
		reply := common.WriteReply{}
		conf := c.config.Load().(ClientConfig)
		select {
		case req = <-c.pendingWrites:
			break
		default:
			req = c.generateRandomWrite(conf)
		}
		err := c.leader.Write(req, &reply)
		if err != nil {
			reply.Err = err.Error()
		}
		if reply.GlobalSeqNo > c.lastSeqNo {
			c.lastSeqNo = reply.GlobalSeqNo
		}
		if req.ReplyChan != nil {
			req.ReplyChan <- &reply
		}
		//TODO: switch to poisson
		time.Sleep(conf.WriteInterval)
	}
}

func (c *Client) readPeriodic() {
	var req request

	for atomic.LoadInt32(&c.dead) == 0 {
		reply := common.ReadReply{}
		conf := c.config.Load().(ClientConfig)
		select {
		case req = <-c.pendingReads:
			break
		default:
			req = c.nextRequest(&conf)
		}
		encreq, err := req.ReadArgs.Encode(conf.TrustDomains)
		if err != nil {
			reply.Err = err.Error()
		} else {
			err := c.leader.Read(&encreq, &reply)
			if err != nil {
				reply.Err = err.Error()
			}
		}
		if reply.GlobalSeqNo.End > c.lastSeqNo {
			c.lastSeqNo = reply.GlobalSeqNo.End
		}
		if req.Subscription != nil {
			req.Subscription.OnResponse(req.ReadArgs, &reply, uint(conf.DataSize))
		}
		time.Sleep(conf.ReadInterval)
	}
}

func (c *Client) generateRandomWrite(config ClientConfig) *common.WriteArgs {
	args := &common.WriteArgs{}
	args.Bucket1 = c.rand.RandomUint64() % config.CommonConfig.NumBuckets
	args.Bucket2 = c.rand.RandomUint64() % config.CommonConfig.NumBuckets
	args.Data = make([]byte, config.CommonConfig.DataSize, config.CommonConfig.DataSize)
	c.rand.FillBytes(args.Data)
	return args
}

func (c *Client) generateRandomRead(config *ClientConfig) *common.ReadArgs {
	args := &common.ReadArgs{}
	vectorSize := uint32((config.CommonConfig.NumBuckets+7)/8 + 1)
	args.TD = make([]common.PirArgs, len(config.TrustDomains), len(config.TrustDomains))
	for i := 0; i < len(args.TD); i++ {
		args.TD[i].RequestVector = make([]byte, vectorSize, vectorSize)
		c.rand.FillBytes(args.TD[i].RequestVector)
		seed, err := drbg.NewSeed()
		if err != nil {
			c.log.Error.Fatalf("Error creating random seed: %v\n", err)
		}
		args.TD[i].PadSeed, err = seed.MarshalBinary()
		if err != nil {
			c.log.Error.Fatalf("Failed to marshal seed: %v\n", err)
		}
	}
	return args
}

func (c *Client) nextRequest(config *ClientConfig) request {
	c.subscriptionMutex.Lock()

	if len(c.subscriptions) > 0 {
		nextTopic := c.subscriptions[0]
		c.subscriptions = c.subscriptions[1:]
		c.subscriptions = append(c.subscriptions, nextTopic)

		ra1, ra2, err := nextTopic.generatePoll(config, c.lastSeqNo)
		if err != nil {
			c.subscriptionMutex.Unlock()
			c.log.Error.Fatal(err)
			return request{c.generateRandomRead(config), nil}
		}
		c.pendingReads <- request{ra2, &nextTopic}
		c.subscriptionMutex.Unlock()
		return request{ra1, &nextTopic}
	}
	c.subscriptionMutex.Unlock()

	return request{c.generateRandomRead(config), nil}
}
<commit_msg>Client random requests directly use crypto.rand per #13<commit_after>package libtalek

import (
	"crypto/rand"
	"errors"
	"math/big"
	"sync"
	"sync/atomic"
	"time"

	"github.com/privacylab/talek/common"
	"github.com/privacylab/talek/drbg"
)

// Client represents a connection to the Talek system. Typically created with
// NewClient, the object manages requests, both reads an writes.
type Client struct {
	log    *common.Logger
	name   string
	config atomic.Value //ClientConfig
	dead   int32
	leader common.LeaderInterface

	subscriptions     []Subscription
	pendingWrites     chan *common.WriteArgs
	pendingReads      chan request
	subscriptionMutex sync.Mutex

	lastSeqNo uint64
}

type request struct {
	*common.ReadArgs
	*Subscription
}

// NewClient creates a Talek client for reading and writing metadata-protected messages.
func NewClient(name string, config ClientConfig, leader common.LeaderInterface) *Client {
	c := &Client{}
	c.log = common.NewLogger(name)
	c.name = name
	c.config.Store(config)
	c.leader = leader

	//todo: should channel capacity be smarter?
	c.pendingReads = make(chan request, 5)
	c.pendingWrites = make(chan *common.WriteArgs, 5)

	go c.readPeriodic()
	go c.writePeriodic()

	c.log.Info.Println("NewClient: starting new client - " + name)
	return c
}

/** PUBLIC METHODS (threadsafe) **/

// SetConfig allows updating the configuraton of a Client, e.g. if server memebership
// or speed characteristics for the system are changed.
func (c *Client) SetConfig(config ClientConfig) {
	c.config.Store(config)
}

// Kill stops client processing. This allows for graceful shutdown or suspension of requests.
func (c *Client) Kill() {
	atomic.StoreInt32(&c.dead, 1)
}

// Ping will perform an on-thread ping of the Talek system, allowing the client
// to validate that it is connected to the Talek system, and check the latency
// of connection to the server.
func (c *Client) Ping() bool {
	var reply common.PingReply
	err := c.leader.Ping(&common.PingArgs{Msg: "PING"}, &reply)
	if err == nil && reply.Err == "" {
		c.log.Info.Printf("Ping success\n")
		return true
	}
	c.log.Warn.Printf("Ping fail: err=%v, reply=%v\n", err, reply)
	return false
}

// MaxLength returns the maximum allowed message the client can Publish.
// TODO: support messages spanning multiple data items.
func (c *Client) MaxLength() int {
	config := c.config.Load().(ClientConfig)
	return config.DataSize
}

// Publish a new message to the end of a topic.
func (c *Client) Publish(handle *Topic, data []byte) error {
	config := c.config.Load().(ClientConfig)

	if len(data) > config.DataSize-PublishingOverhead {
		return errors.New("message too long")
	} else if len(data) < config.DataSize-PublishingOverhead {
		allocation := make([]byte, config.DataSize-PublishingOverhead)
		copy(allocation[:], data)
		data = allocation
	}

	writeArgs, err := handle.GeneratePublish(config.CommonConfig, data)
	c.log.Info.Printf("Wrote %v(%d) to %d,%d.", writeArgs.Data[0:4], len(writeArgs.Data), writeArgs.Bucket1, writeArgs.Bucket2)
	if err != nil {
		return err
	}

	c.pendingWrites <- writeArgs
	return nil
}

// Poll Subscribes to updates on a given log Subscription.
// When done reading message,s the the channel can be closed via the Done
// method.
func (c *Client) Poll(handle *Subscription) chan []byte {
	// Check if already subscribed.
	c.subscriptionMutex.Lock()
	for x := range c.subscriptions {
		if &c.subscriptions[x] == handle {
			c.subscriptionMutex.Unlock()
			return nil
		}
	}
	c.subscriptions = append(c.subscriptions, *handle)
	c.subscriptionMutex.Unlock()

	return handle.Updates
}

// Done unsubscribes a Subscription from being Polled for new items.
func (c *Client) Done(handle *Subscription) bool {
	c.subscriptionMutex.Lock()
	for i := 0; i < len(c.subscriptions); i++ {
		if &c.subscriptions[i] == handle {
			c.subscriptions[i] = c.subscriptions[len(c.subscriptions)-1]
			c.subscriptions = c.subscriptions[:len(c.subscriptions)-1]
			c.subscriptionMutex.Unlock()
			return true
		}
	}
	c.subscriptionMutex.Unlock()
	return false
}

/** Private methods **/
func (c *Client) writePeriodic() {
	var req *common.WriteArgs

	for atomic.LoadInt32(&c.dead) == 0 {
		reply := common.WriteReply{}
		conf := c.config.Load().(ClientConfig)
		select {
		case req = <-c.pendingWrites:
			break
		default:
			req = c.generateRandomWrite(conf)
		}
		err := c.leader.Write(req, &reply)
		if err != nil {
			reply.Err = err.Error()
		}
		if reply.GlobalSeqNo > c.lastSeqNo {
			c.lastSeqNo = reply.GlobalSeqNo
		}
		if req.ReplyChan != nil {
			req.ReplyChan <- &reply
		}
		//TODO: switch to poisson
		time.Sleep(conf.WriteInterval)
	}
}

func (c *Client) readPeriodic() {
	var req request

	for atomic.LoadInt32(&c.dead) == 0 {
		reply := common.ReadReply{}
		conf := c.config.Load().(ClientConfig)
		select {
		case req = <-c.pendingReads:
			break
		default:
			req = c.nextRequest(&conf)
		}
		encreq, err := req.ReadArgs.Encode(conf.TrustDomains)
		if err != nil {
			reply.Err = err.Error()
		} else {
			err := c.leader.Read(&encreq, &reply)
			if err != nil {
				reply.Err = err.Error()
			}
		}
		if reply.GlobalSeqNo.End > c.lastSeqNo {
			c.lastSeqNo = reply.GlobalSeqNo.End
		}
		if req.Subscription != nil {
			req.Subscription.OnResponse(req.ReadArgs, &reply, uint(conf.DataSize))
		}
		time.Sleep(conf.ReadInterval)
	}
}

func (c *Client) generateRandomWrite(config ClientConfig) *common.WriteArgs {
	args := &common.WriteArgs{}
	var max big.Int
	b1, _ := rand.Int(rand.Reader, max.SetUint64(config.NumBuckets))
	b2, _ := rand.Int(rand.Reader, max.SetUint64(config.NumBuckets))
	args.Bucket1 = b1.Uint64()
	args.Bucket2 = b2.Uint64()
	args.Data = make([]byte, config.CommonConfig.DataSize, config.CommonConfig.DataSize)
	rand.Read(args.Data)
	return args
}

func (c *Client) generateRandomRead(config *ClientConfig) *common.ReadArgs {
	args := &common.ReadArgs{}
	vectorSize := uint32((config.CommonConfig.NumBuckets+7)/8 + 1)
	args.TD = make([]common.PirArgs, len(config.TrustDomains), len(config.TrustDomains))
	for i := 0; i < len(args.TD); i++ {
		args.TD[i].RequestVector = make([]byte, vectorSize, vectorSize)
		rand.Read(args.TD[i].RequestVector)
		seed, err := drbg.NewSeed()
		if err != nil {
			c.log.Error.Fatalf("Error creating random seed: %v\n", err)
		}
		args.TD[i].PadSeed, err = seed.MarshalBinary()
		if err != nil {
			c.log.Error.Fatalf("Failed to marshal seed: %v\n", err)
		}
	}
	return args
}

func (c *Client) nextRequest(config *ClientConfig) request {
	c.subscriptionMutex.Lock()

	if len(c.subscriptions) > 0 {
		nextTopic := c.subscriptions[0]
		c.subscriptions = c.subscriptions[1:]
		c.subscriptions = append(c.subscriptions, nextTopic)

		ra1, ra2, err := nextTopic.generatePoll(config, c.lastSeqNo)
		if err != nil {
			c.subscriptionMutex.Unlock()
			c.log.Error.Fatal(err)
			return request{c.generateRandomRead(config), nil}
		}
		c.pendingReads <- request{ra2, &nextTopic}
		c.subscriptionMutex.Unlock()
		return request{ra1, &nextTopic}
	}
	c.subscriptionMutex.Unlock()

	return request{c.generateRandomRead(config), nil}
}
<|endoftext|>


<commit_before>package uri

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/user"
	"strings"
	"time"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
	"golang.org/x/crypto/ssh/knownhosts"
)

const (
	defaultSSHPort           = "22"
	defaultSSHKeyPath        = "${HOME}/.ssh/id_rsa"
	defaultSSHKnownHostsPath = "${HOME}/.ssh/known_hosts"
	defaultSSHAuthMethods    = "agent,privkey"
)

func (curi *ConnectionURI) parseAuthMethods() []ssh.AuthMethod {
	q := curi.Query()

	authMethods := q.Get("sshauth")
	if authMethods == "" {
		authMethods = defaultSSHAuthMethods
	}

	sshKeyPath := q.Get("keyfile")
	if sshKeyPath == "" {
		sshKeyPath = defaultSSHKeyPath
	}

	auths := strings.Split(authMethods, ",")
	result := make([]ssh.AuthMethod, 0)
	for _, v := range auths {
		switch v {
		case "agent":
			socket := os.Getenv("SSH_AUTH_SOCK")
			if socket == "" {
				continue
			}
			conn, err := net.Dial("unix", socket)
			// Ignore error, we just fall back to another auth method
			if err != nil {
				log.Printf("[ERROR] Unable to connect to SSH agent: %v", err)
				continue
			}
			agentClient := agent.NewClient(conn)
			result = append(result, ssh.PublicKeysCallback(agentClient.Signers))
		case "privkey":
			sshKey, err := ioutil.ReadFile(os.ExpandEnv(sshKeyPath))
			if err != nil {
				log.Printf("[ERROR] Failed to read ssh key: %v", err)
				continue
			}

			signer, err := ssh.ParsePrivateKey(sshKey)
			if err != nil {
				log.Printf("[ERROR] Failed to parse ssh key: %v", err)
			}
			result = append(result, ssh.PublicKeys(signer))
		case "ssh-password":
			if sshPassword, ok := curi.User.Password(); ok {
				result = append(result, ssh.Password(sshPassword))
			} else {
				log.Printf("[ERROR] Missing password in userinfo of URI authority section")
			}
		default:
			// For future compatibility it's better to just warn and not error
			log.Printf("[WARN] Unsupported auth method: %s", v)
		}
	}

	return result
}

func (curi *ConnectionURI) dialSSH() (net.Conn, error) {
	authMethods := curi.parseAuthMethods()
	if len(authMethods) < 1 {
		return nil, fmt.Errorf("Could not configure SSH authentication methods")
	}
	q := curi.Query()

	knownHostsPath := q.Get("knownhosts")
	knownHostsVerify := q.Get("known_hosts_verify")
	doVerify := q.Get("no_verify") == ""

	if knownHostsVerify == "ignore" {
		doVerify = false
	}

	if knownHostsPath == "" {
		knownHostsPath = defaultSSHKnownHostsPath
	}

	hostKeyCallback := ssh.InsecureIgnoreHostKey()
	if doVerify {
		cb, err := knownhosts.New(os.ExpandEnv(knownHostsPath))
		if err != nil {
			return nil, fmt.Errorf("failed to read ssh known hosts: %w", err)
		}
		hostKeyCallback = cb
	}

	username := curi.User.Username()
	if username == "" {
		u, err := user.Current()
		if err != nil {
			return nil, err
		}
		username = u.Username
	}

	cfg := ssh.ClientConfig{
		User:            username,
		HostKeyCallback: hostKeyCallback,
		Auth:            authMethods,
		Timeout:         2 * time.Second,
	}

	port := curi.Port()
	if port == "" {
		port = defaultSSHPort
	}

	sshClient, err := ssh.Dial("tcp", fmt.Sprintf("%s:%s", curi.Hostname(), port), &cfg)
	if err != nil {
		return nil, err
	}

	address := q.Get("socket")
	if address == "" {
		address = defaultUnixSock
	}

	c, err := sshClient.Dial("unix", address)
	if err != nil {
		return nil, fmt.Errorf("failed to connect to libvirt on the remote host: %w", err)
	}

	return c, nil
}
<commit_msg>stylecheck: ST1016: methods on the same type should have the same receiver name<commit_after>package uri

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/user"
	"strings"
	"time"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
	"golang.org/x/crypto/ssh/knownhosts"
)

const (
	defaultSSHPort           = "22"
	defaultSSHKeyPath        = "${HOME}/.ssh/id_rsa"
	defaultSSHKnownHostsPath = "${HOME}/.ssh/known_hosts"
	defaultSSHAuthMethods    = "agent,privkey"
)

func (u *ConnectionURI) parseAuthMethods() []ssh.AuthMethod {
	q := u.Query()

	authMethods := q.Get("sshauth")
	if authMethods == "" {
		authMethods = defaultSSHAuthMethods
	}

	sshKeyPath := q.Get("keyfile")
	if sshKeyPath == "" {
		sshKeyPath = defaultSSHKeyPath
	}

	auths := strings.Split(authMethods, ",")
	result := make([]ssh.AuthMethod, 0)
	for _, v := range auths {
		switch v {
		case "agent":
			socket := os.Getenv("SSH_AUTH_SOCK")
			if socket == "" {
				continue
			}
			conn, err := net.Dial("unix", socket)
			// Ignore error, we just fall back to another auth method
			if err != nil {
				log.Printf("[ERROR] Unable to connect to SSH agent: %v", err)
				continue
			}
			agentClient := agent.NewClient(conn)
			result = append(result, ssh.PublicKeysCallback(agentClient.Signers))
		case "privkey":
			sshKey, err := ioutil.ReadFile(os.ExpandEnv(sshKeyPath))
			if err != nil {
				log.Printf("[ERROR] Failed to read ssh key: %v", err)
				continue
			}

			signer, err := ssh.ParsePrivateKey(sshKey)
			if err != nil {
				log.Printf("[ERROR] Failed to parse ssh key: %v", err)
			}
			result = append(result, ssh.PublicKeys(signer))
		case "ssh-password":
			if sshPassword, ok := u.User.Password(); ok {
				result = append(result, ssh.Password(sshPassword))
			} else {
				log.Printf("[ERROR] Missing password in userinfo of URI authority section")
			}
		default:
			// For future compatibility it's better to just warn and not error
			log.Printf("[WARN] Unsupported auth method: %s", v)
		}
	}

	return result
}

func (u *ConnectionURI) dialSSH() (net.Conn, error) {
	authMethods := u.parseAuthMethods()
	if len(authMethods) < 1 {
		return nil, fmt.Errorf("Could not configure SSH authentication methods")
	}
	q := u.Query()

	knownHostsPath := q.Get("knownhosts")
	knownHostsVerify := q.Get("known_hosts_verify")
	doVerify := q.Get("no_verify") == ""

	if knownHostsVerify == "ignore" {
		doVerify = false
	}

	if knownHostsPath == "" {
		knownHostsPath = defaultSSHKnownHostsPath
	}

	hostKeyCallback := ssh.InsecureIgnoreHostKey()
	if doVerify {
		cb, err := knownhosts.New(os.ExpandEnv(knownHostsPath))
		if err != nil {
			return nil, fmt.Errorf("failed to read ssh known hosts: %w", err)
		}
		hostKeyCallback = cb
	}

	username := u.User.Username()
	if username == "" {
		u, err := user.Current()
		if err != nil {
			return nil, err
		}
		username = u.Username
	}

	cfg := ssh.ClientConfig{
		User:            username,
		HostKeyCallback: hostKeyCallback,
		Auth:            authMethods,
		Timeout:         2 * time.Second,
	}

	port := u.Port()
	if port == "" {
		port = defaultSSHPort
	}

	sshClient, err := ssh.Dial("tcp", fmt.Sprintf("%s:%s", u.Hostname(), port), &cfg)
	if err != nil {
		return nil, err
	}

	address := q.Get("socket")
	if address == "" {
		address = defaultUnixSock
	}

	c, err := sshClient.Dial("unix", address)
	if err != nil {
		return nil, fmt.Errorf("failed to connect to libvirt on the remote host: %w", err)
	}

	return c, nil
}
<|endoftext|>


<commit_before>package huffman

type HuffmanCode struct {
	Code   uint32
	BitLen byte
}

type Node struct {
	Left, Right *Node
	Code        int16
}

var HUFFMAN_TABLE *[257]HuffmanCode = &[257]HuffmanCode{
	{0x1ff8, 13},
	{0x7fffd8, 23},
	{0xfffffe2, 28},
	{0xfffffe3, 28},
	{0xfffffe4, 28},
	{0xfffffe5, 28},
	{0xfffffe6, 28},
	{0xfffffe7, 28},
	{0xfffffe8, 28},
	{0xffffea, 24},
	{0x3ffffffc, 30},
	{0xfffffe9, 28},
	{0xfffffea, 28},
	{0x3ffffffd, 30},
	{0xfffffeb, 28},
	{0xfffffec, 28},
	{0xfffffed, 28},
	{0xfffffee, 28},
	{0xfffffef, 28},
	{0xffffff0, 28},
	{0xffffff1, 28},
	{0xffffff2, 28},
	{0x3ffffffe, 30},
	{0xffffff3, 28},
	{0xffffff4, 28},
	{0xffffff5, 28},
	{0xffffff6, 28},
	{0xffffff7, 28},
	{0xffffff8, 28},
	{0xffffff9, 28},
	{0xffffffa, 28},
	{0xffffffb, 28},
	{0x14, 6},
	{0x3f8, 10},
	{0x3f9, 10},
	{0xffa, 12},
	{0x1ff9, 13},
	{0x15, 6},
	{0xf8, 8},
	{0x7fa, 11},
	{0x3fa, 10},
	{0x3fb, 10},
	{0xf9, 8},
	{0x7fb, 11},
	{0xfa, 8},
	{0x16, 6},
	{0x17, 6},
	{0x18, 6},
	{0x0, 5},
	{0x1, 5},
	{0x2, 5},
	{0x19, 6},
	{0x1a, 6},
	{0x1b, 6},
	{0x1c, 6},
	{0x1d, 6},
	{0x1e, 6},
	{0x1f, 6},
	{0x5c, 7},
	{0xfb, 8},
	{0x7ffc, 15},
	{0x20, 6},
	{0xffb, 12},
	{0x3fc, 10},
	{0x1ffa, 13},
	{0x21, 6},
	{0x5d, 7},
	{0x5e, 7},
	{0x5f, 7},
	{0x60, 7},
	{0x61, 7},
	{0x62, 7},
	{0x63, 7},
	{0x64, 7},
	{0x65, 7},
	{0x66, 7},
	{0x67, 7},
	{0x68, 7},
	{0x69, 7},
	{0x6a, 7},
	{0x6b, 7},
	{0x6c, 7},
	{0x6d, 7},
	{0x6e, 7},
	{0x6f, 7},
	{0x70, 7},
	{0x71, 7},
	{0x72, 7},
	{0xfc, 8},
	{0x73, 7},
	{0xfd, 8},
	{0x1ffb, 13},
	{0x7fff0, 19},
	{0x1ffc, 13},
	{0x3ffc, 14},
	{0x22, 6},
	{0x7ffd, 15},
	{0x3, 5},
	{0x23, 6},
	{0x4, 5},
	{0x24, 6},
	{0x5, 5},
	{0x25, 6},
	{0x26, 6},
	{0x27, 6},
	{0x6, 5},
	{0x74, 7},
	{0x75, 7},
	{0x28, 6},
	{0x29, 6},
	{0x2a, 6},
	{0x7, 5},
	{0x2b, 6},
	{0x76, 7},
	{0x2c, 6},
	{0x8, 5},
	{0x9, 5},
	{0x2d, 6},
	{0x77, 7},
	{0x78, 7},
	{0x79, 7},
	{0x7a, 7},
	{0x7b, 7},
	{0x7ffe, 15},
	{0x7fc, 11},
	{0x3ffd, 14},
	{0x1ffd, 13},
	{0xffffffc, 28},
	{0xfffe6, 20},
	{0x3fffd2, 22},
	{0xfffe7, 20},
	{0xfffe8, 20},
	{0x3fffd3, 22},
	{0x3fffd4, 22},
	{0x3fffd5, 22},
	{0x7fffd9, 23},
	{0x3fffd6, 22},
	{0x7fffda, 23},
	{0x7fffdb, 23},
	{0x7fffdc, 23},
	{0x7fffdd, 23},
	{0x7fffde, 23},
	{0xffffeb, 23},
	{0x7fffdf, 23},
	{0xffffec, 24},
	{0xffffed, 24},
	{0x3fffd7, 22},
	{0x7fffe0, 23},
	{0xffffee, 24},
	{0x7fffe1, 23},
	{0x7fffe2, 23},
	{0x7fffe3, 23},
	{0x7fffe4, 23},
	{0x1fffdc, 21},
	{0x3fffd8, 22},
	{0x7fffe5, 23},
	{0x3fffd9, 22},
	{0x7fffe6, 23},
	{0x7fffe7, 23},
	{0xffffef, 24},
	{0x3fffda, 22},
	{0x1fffdd, 21},
	{0xfffe9, 20},
	{0x3fffdb, 22},
	{0x3fffdc, 22},
	{0x7fffe8, 23},
	{0x7fffe9, 23},
	{0x1fffde, 21},
	{0x7fffde, 23},
	{0x3fffdd, 22},
	{0x3fffde, 22},
	{0xfffff0, 24},
	{0x1fffdf, 21},
	{0x3fffdf, 22},
	{0x7fffeb, 23},
	{0x7fffec, 23},
	{0x1fffe0, 21},
	{0x1fffe1, 21},
	{0x3fffe0, 22},
	{0x1fffe2, 21},
	{0x7fffed, 23},
	{0x3fffe1, 22},
	{0x7fffee, 23},
	{0x7fffef, 23},
	{0xfffea, 20},
	{0x3fffe2, 22},
	{0x3fffe3, 22},
	{0x3fffe4, 22},
	{0x7ffff0, 23},
	{0x3fffe5, 22},
	{0x3fffe6, 22},
	{0x7ffff1, 23},
	{0x3ffffe0, 26},
	{0x3ffffe1, 26},
	{0xfffeb, 20},
	{0x7fff1, 19},
	{0x3fffe7, 22},
	{0x7ffff2, 23},
	{0x3fffe8, 22},
	{0x1ffffec, 25},
	{0x3ffffe2, 26},
	{0x3ffffe3, 26},
	{0x3ffffe4, 26},
	{0x7ffffde, 27},
	{0x7ffffdf, 27},
	{0x3ffffe5, 26},
	{0xfffff1, 24},
	{0x1ffffed, 25},
	{0x7fff2, 19},
	{0x1fffe3, 21},
	{0x3ffffe6, 26},
	{0x7ffffe0, 27},
	{0x7ffffe1, 27},
	{0x3ffffe7, 26},
	{0x3ffffe2, 27},
	{0xfffff2, 24},
	{0x1fffe4, 21},
	{0x1fffe5, 21},
	{0x3ffffe8, 26},
	{0x3ffffe9, 26},
	{0xffffffd, 28},
	{0x7ffffe3, 27},
	{0x7ffffe4, 27},
	{0x7ffffe5, 27},
	{0xfffec, 20},
	{0xfffff3, 24},
	{0xfffed, 20},
	{0x1fffe6, 21},
	{0x3fffe9, 22},
	{0x1fffe7, 21},
	{0x1fffe8, 21},
	{0x7ffff3, 23},
	{0x3fffea, 22},
	{0x3fffeb, 22},
	{0x1ffffee, 25},
	{0x1ffffef, 25},
	{0xfffff4, 24},
	{0xfffff5, 24},
	{0x3ffffea, 26},
	{0x7ffff4, 23},
	{0x3ffffeb, 26},
	{0x7ffffe6, 27},
	{0x3ffffec, 26},
	{0x3ffffed, 26},
	{0x7ffffe7, 27},
	{0x7ffffe8, 27},
	{0x7ffffe9, 27},
	{0x7ffffea, 27},
	{0x7ffffeb, 27},
	{0xffffffe, 28},
	{0x7ffffec, 27},
	{0x7ffffed, 27},
	{0x7ffffee, 27},
	{0x7ffffef, 27},
	{0x7fffff0, 27},
	{0x3ffffee, 26},
	{0x3fffffff, 30},
}

var Root Node = Node{nil, nil, -1}

func (root *Node) CreateTree() {
	for code, huff := range HUFFMAN_TABLE {
		cursor := root
		for i := huff.BitLen; i > 0; i-- {
			if huff.Code&(1<<(i-1)) > 0 {
				if cursor.Right == nil {
					cursor.Right = &Node{nil, nil, -1}
				}
				cursor = cursor.Right
			} else {
				if cursor.Left == nil {
					cursor.Left = &Node{nil, nil, -1}
				}
				cursor = cursor.Left
			}
		}
		cursor.Code = int16(code)
	}
}

func (root *Node) Encode(content string) (dist string, length uint32) {
	var hContent uint32 = 0
	asciis := []byte(content)
	for _, ascii := range asciis {
		hContent <<= HUFFMAN_TABLE[ascii].BitLen
		hContent |= HUFFMAN_TABLE[ascii].Code
		length += uint32(HUFFMAN_TABLE[ascii].BitLen)
	}

	endPad := (8 - (length % 8)) % 8
	if endPad > 0 {
		hContent <<= endPad
		hContent |= ((1 << endPad) - 1)
		length += endPad
	}
	return
}

func (root *Node) Decode(buf []byte, length uint32) (content string) {
	cursor := root
	for i := 0; uint32(i) < length; i++ {
		for j := 7; j >= 0; j-- {
			if buf[i]&(1<<byte(j)) > 0 {
				cursor = cursor.Right
			} else {
				cursor = cursor.Left
			}
			if cursor.Code >= 0 {
				content += string(cursor.Code)
				cursor = root
			}
		}
	}
	return content
}
<commit_msg>fix bug for longer content<commit_after>package huffman

type HuffmanCode struct {
	Code   uint32
	BitLen byte
}

type Node struct {
	Left, Right *Node
	Code        int16
}

var HUFFMAN_TABLE *[257]HuffmanCode = &[257]HuffmanCode{
	{0x1ff8, 13},
	{0x7fffd8, 23},
	{0xfffffe2, 28},
	{0xfffffe3, 28},
	{0xfffffe4, 28},
	{0xfffffe5, 28},
	{0xfffffe6, 28},
	{0xfffffe7, 28},
	{0xfffffe8, 28},
	{0xffffea, 24},
	{0x3ffffffc, 30},
	{0xfffffe9, 28},
	{0xfffffea, 28},
	{0x3ffffffd, 30},
	{0xfffffeb, 28},
	{0xfffffec, 28},
	{0xfffffed, 28},
	{0xfffffee, 28},
	{0xfffffef, 28},
	{0xffffff0, 28},
	{0xffffff1, 28},
	{0xffffff2, 28},
	{0x3ffffffe, 30},
	{0xffffff3, 28},
	{0xffffff4, 28},
	{0xffffff5, 28},
	{0xffffff6, 28},
	{0xffffff7, 28},
	{0xffffff8, 28},
	{0xffffff9, 28},
	{0xffffffa, 28},
	{0xffffffb, 28},
	{0x14, 6},
	{0x3f8, 10},
	{0x3f9, 10},
	{0xffa, 12},
	{0x1ff9, 13},
	{0x15, 6},
	{0xf8, 8},
	{0x7fa, 11},
	{0x3fa, 10},
	{0x3fb, 10},
	{0xf9, 8},
	{0x7fb, 11},
	{0xfa, 8},
	{0x16, 6},
	{0x17, 6},
	{0x18, 6},
	{0x0, 5},
	{0x1, 5},
	{0x2, 5},
	{0x19, 6},
	{0x1a, 6},
	{0x1b, 6},
	{0x1c, 6},
	{0x1d, 6},
	{0x1e, 6},
	{0x1f, 6},
	{0x5c, 7},
	{0xfb, 8},
	{0x7ffc, 15},
	{0x20, 6},
	{0xffb, 12},
	{0x3fc, 10},
	{0x1ffa, 13},
	{0x21, 6},
	{0x5d, 7},
	{0x5e, 7},
	{0x5f, 7},
	{0x60, 7},
	{0x61, 7},
	{0x62, 7},
	{0x63, 7},
	{0x64, 7},
	{0x65, 7},
	{0x66, 7},
	{0x67, 7},
	{0x68, 7},
	{0x69, 7},
	{0x6a, 7},
	{0x6b, 7},
	{0x6c, 7},
	{0x6d, 7},
	{0x6e, 7},
	{0x6f, 7},
	{0x70, 7},
	{0x71, 7},
	{0x72, 7},
	{0xfc, 8},
	{0x73, 7},
	{0xfd, 8},
	{0x1ffb, 13},
	{0x7fff0, 19},
	{0x1ffc, 13},
	{0x3ffc, 14},
	{0x22, 6},
	{0x7ffd, 15},
	{0x3, 5},
	{0x23, 6},
	{0x4, 5},
	{0x24, 6},
	{0x5, 5},
	{0x25, 6},
	{0x26, 6},
	{0x27, 6},
	{0x6, 5},
	{0x74, 7},
	{0x75, 7},
	{0x28, 6},
	{0x29, 6},
	{0x2a, 6},
	{0x7, 5},
	{0x2b, 6},
	{0x76, 7},
	{0x2c, 6},
	{0x8, 5},
	{0x9, 5},
	{0x2d, 6},
	{0x77, 7},
	{0x78, 7},
	{0x79, 7},
	{0x7a, 7},
	{0x7b, 7},
	{0x7ffe, 15},
	{0x7fc, 11},
	{0x3ffd, 14},
	{0x1ffd, 13},
	{0xffffffc, 28},
	{0xfffe6, 20},
	{0x3fffd2, 22},
	{0xfffe7, 20},
	{0xfffe8, 20},
	{0x3fffd3, 22},
	{0x3fffd4, 22},
	{0x3fffd5, 22},
	{0x7fffd9, 23},
	{0x3fffd6, 22},
	{0x7fffda, 23},
	{0x7fffdb, 23},
	{0x7fffdc, 23},
	{0x7fffdd, 23},
	{0x7fffde, 23},
	{0xffffeb, 23},
	{0x7fffdf, 23},
	{0xffffec, 24},
	{0xffffed, 24},
	{0x3fffd7, 22},
	{0x7fffe0, 23},
	{0xffffee, 24},
	{0x7fffe1, 23},
	{0x7fffe2, 23},
	{0x7fffe3, 23},
	{0x7fffe4, 23},
	{0x1fffdc, 21},
	{0x3fffd8, 22},
	{0x7fffe5, 23},
	{0x3fffd9, 22},
	{0x7fffe6, 23},
	{0x7fffe7, 23},
	{0xffffef, 24},
	{0x3fffda, 22},
	{0x1fffdd, 21},
	{0xfffe9, 20},
	{0x3fffdb, 22},
	{0x3fffdc, 22},
	{0x7fffe8, 23},
	{0x7fffe9, 23},
	{0x1fffde, 21},
	{0x7fffde, 23},
	{0x3fffdd, 22},
	{0x3fffde, 22},
	{0xfffff0, 24},
	{0x1fffdf, 21},
	{0x3fffdf, 22},
	{0x7fffeb, 23},
	{0x7fffec, 23},
	{0x1fffe0, 21},
	{0x1fffe1, 21},
	{0x3fffe0, 22},
	{0x1fffe2, 21},
	{0x7fffed, 23},
	{0x3fffe1, 22},
	{0x7fffee, 23},
	{0x7fffef, 23},
	{0xfffea, 20},
	{0x3fffe2, 22},
	{0x3fffe3, 22},
	{0x3fffe4, 22},
	{0x7ffff0, 23},
	{0x3fffe5, 22},
	{0x3fffe6, 22},
	{0x7ffff1, 23},
	{0x3ffffe0, 26},
	{0x3ffffe1, 26},
	{0xfffeb, 20},
	{0x7fff1, 19},
	{0x3fffe7, 22},
	{0x7ffff2, 23},
	{0x3fffe8, 22},
	{0x1ffffec, 25},
	{0x3ffffe2, 26},
	{0x3ffffe3, 26},
	{0x3ffffe4, 26},
	{0x7ffffde, 27},
	{0x7ffffdf, 27},
	{0x3ffffe5, 26},
	{0xfffff1, 24},
	{0x1ffffed, 25},
	{0x7fff2, 19},
	{0x1fffe3, 21},
	{0x3ffffe6, 26},
	{0x7ffffe0, 27},
	{0x7ffffe1, 27},
	{0x3ffffe7, 26},
	{0x3ffffe2, 27},
	{0xfffff2, 24},
	{0x1fffe4, 21},
	{0x1fffe5, 21},
	{0x3ffffe8, 26},
	{0x3ffffe9, 26},
	{0xffffffd, 28},
	{0x7ffffe3, 27},
	{0x7ffffe4, 27},
	{0x7ffffe5, 27},
	{0xfffec, 20},
	{0xfffff3, 24},
	{0xfffed, 20},
	{0x1fffe6, 21},
	{0x3fffe9, 22},
	{0x1fffe7, 21},
	{0x1fffe8, 21},
	{0x7ffff3, 23},
	{0x3fffea, 22},
	{0x3fffeb, 22},
	{0x1ffffee, 25},
	{0x1ffffef, 25},
	{0xfffff4, 24},
	{0xfffff5, 24},
	{0x3ffffea, 26},
	{0x7ffff4, 23},
	{0x3ffffeb, 26},
	{0x7ffffe6, 27},
	{0x3ffffec, 26},
	{0x3ffffed, 26},
	{0x7ffffe7, 27},
	{0x7ffffe8, 27},
	{0x7ffffe9, 27},
	{0x7ffffea, 27},
	{0x7ffffeb, 27},
	{0xffffffe, 28},
	{0x7ffffec, 27},
	{0x7ffffed, 27},
	{0x7ffffee, 27},
	{0x7ffffef, 27},
	{0x7fffff0, 27},
	{0x3ffffee, 26},
	{0x3fffffff, 30},
}

var Root Node = Node{nil, nil, -1}

func (root *Node) CreateTree() {
	for code, huff := range HUFFMAN_TABLE {
		cursor := root
		for i := huff.BitLen; i > 0; i-- {
			if huff.Code&(1<<(i-1)) > 0 {
				if cursor.Right == nil {
					cursor.Right = &Node{nil, nil, -1}
				}
				cursor = cursor.Right
			} else {
				if cursor.Left == nil {
					cursor.Left = &Node{nil, nil, -1}
				}
				cursor = cursor.Left
			}
		}
		cursor.Code = int16(code)
	}
}

func (root *Node) Encode(content string) (dist []byte, length uint32) {
	var buf byte
	var bufRest byte = 8
	asciis := []byte(content)
	for _, ascii := range asciis {
		huff := HUFFMAN_TABLE[ascii]

		for huff.BitLen > 0 {
			if huff.BitLen < bufRest {
				bufRest -= huff.BitLen
				buf |= byte(huff.Code << bufRest)
				huff.BitLen = 0
			} else {
				shift := huff.BitLen - bufRest
				buf |= byte(huff.Code >> shift)
				huff.BitLen -= bufRest
				bufRest = 0
				huff.Code = huff.Code & ((1 << shift) - 1)
			}
			if bufRest == 0 {
				dist = append(dist, buf)
				buf = 0
				bufRest = 8
				length++
			}
		}
	}
	if bufRest > 0 && bufRest < 8 {
		buf |= ((1 << bufRest) - 1)
		dist = append(dist, buf)
		length++
	}

	return
}

func (root *Node) Decode(buf []byte, length uint32) (content string) {
	cursor := root
	for i := 0; uint32(i) < length; i++ {
		for j := 7; j >= 0; j-- {
			if buf[i]&(1<<byte(j)) > 0 {
				cursor = cursor.Right
			} else {
				cursor = cursor.Left
			}
			if cursor.Code >= 0 {
				content += string(cursor.Code)
				cursor = root
			}
		}
	}
	return content
}
<|endoftext|>


<commit_before>package util

import (
	"bufio"
	"io"
	"net"
	"net/http"
)

// WriterProxy is a proxy around an http.ResponseWriter that allows you to hook
// into various parts of the response process.
type WriterProxy interface {
	http.ResponseWriter
	// Status returns the HTTP status of the request, or 0 if one has not
	// yet been sent.
	Status() int
	// Tee causes the response body to be written to the given io.Writer in
	// addition to proxying the writes through. Only one io.Writer can be
	// tee'd to at once: setting a second one will overwrite the first.
	// Writes will be sent to the proxy before being written to this
	// io.Writer. It is illegal for the tee'd writer to be modified
	// concurrently with writes.
	Tee(io.Writer)
	// Unwrap returns the original proxied target.
	Unwrap() http.ResponseWriter
}

// WrapWriter wraps an http.ResponseWriter into a proxy that allows you to hook
// into various parts of the response process.
func WrapWriter(w http.ResponseWriter) WriterProxy {
	_, cn := w.(http.CloseNotifier)
	_, fl := w.(http.Flusher)
	_, hj := w.(http.Hijacker)
	_, rf := w.(io.ReaderFrom)

	bw := basicWriter{ResponseWriter: w}
	if cn && fl && hj && rf {
		return &fancyWriter{bw}
	}
	return &bw
}

// basicWriter wraps a http.ResponseWriter that implements the minimal
// http.ResponseWriter interface.
type basicWriter struct {
	http.ResponseWriter
	wroteHeader bool
	code        int
	tee         io.Writer
}

func (b *basicWriter) WriteHeader(code int) {
	if !b.wroteHeader {
		b.code = code
		b.wroteHeader = true
		b.ResponseWriter.WriteHeader(code)
	}
}
func (b *basicWriter) Write(buf []byte) (int, error) {
	b.WriteHeader(http.StatusOK)
	n, err := b.ResponseWriter.Write(buf)
	if b.tee != nil {
		_, err2 := b.tee.Write(buf[:n])
		// Prefer errors generated by the proxied writer.
		if err == nil {
			err = err2
		}
	}
	return n, err
}
func (b *basicWriter) maybeWriteHeader() {
	if !b.wroteHeader {
		b.WriteHeader(http.StatusOK)
	}
}
func (b *basicWriter) Status() int {
	return b.code
}
func (b *basicWriter) Tee(w io.Writer) {
	b.tee = w
}
func (b *basicWriter) Unwrap() http.ResponseWriter {
	return b.ResponseWriter
}

// fancyWriter is a writer that additionally satisfies http.CloseNotifier,
// http.Flusher, http.Hijacker, and io.ReaderFrom. It exists for the common case
// of wrapping the http.ResponseWriter that package http gives you, in order to
// make the proxied object support the full method set of the proxied object.
type fancyWriter struct {
	basicWriter
}

func (f *fancyWriter) CloseNotify() <-chan bool {
	cn := f.basicWriter.ResponseWriter.(http.CloseNotifier)
	return cn.CloseNotify()
}
func (f *fancyWriter) Flush() {
	fl := f.basicWriter.ResponseWriter.(http.Flusher)
	fl.Flush()
}
func (f *fancyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	hj := f.basicWriter.ResponseWriter.(http.Hijacker)
	return hj.Hijack()
}
func (f *fancyWriter) ReadFrom(r io.Reader) (int64, error) {
	if f.basicWriter.tee != nil {
		return io.Copy(&f.basicWriter, r)
	}
	rf := f.basicWriter.ResponseWriter.(io.ReaderFrom)
	f.basicWriter.maybeWriteHeader()
	return rf.ReadFrom(r)
}

var _ http.CloseNotifier = &fancyWriter{}
var _ http.Flusher = &fancyWriter{}
var _ http.Hijacker = &fancyWriter{}
var _ io.ReaderFrom = &fancyWriter{}
<commit_msg>Add BytesWritten() method to WriterProxy.<commit_after>package util

import (
	"bufio"
	"io"
	"net"
	"net/http"
)

// WriterProxy is a proxy around an http.ResponseWriter that allows you to hook
// into various parts of the response process.
type WriterProxy interface {
	http.ResponseWriter
	// Status returns the HTTP status of the request, or 0 if one has not
	// yet been sent.
	Status() int
	// BytesWritten returns the total number of bytes sent to the client.
	BytesWritten() int
	// Tee causes the response body to be written to the given io.Writer in
	// addition to proxying the writes through. Only one io.Writer can be
	// tee'd to at once: setting a second one will overwrite the first.
	// Writes will be sent to the proxy before being written to this
	// io.Writer. It is illegal for the tee'd writer to be modified
	// concurrently with writes.
	Tee(io.Writer)
	// Unwrap returns the original proxied target.
	Unwrap() http.ResponseWriter
}

// WrapWriter wraps an http.ResponseWriter into a proxy that allows you to hook
// into various parts of the response process.
func WrapWriter(w http.ResponseWriter) WriterProxy {
	_, cn := w.(http.CloseNotifier)
	_, fl := w.(http.Flusher)
	_, hj := w.(http.Hijacker)
	_, rf := w.(io.ReaderFrom)

	bw := basicWriter{ResponseWriter: w}
	if cn && fl && hj && rf {
		return &fancyWriter{bw}
	}
	return &bw
}

// basicWriter wraps a http.ResponseWriter that implements the minimal
// http.ResponseWriter interface.
type basicWriter struct {
	http.ResponseWriter
	wroteHeader bool
	code        int
	bytes       int
	tee         io.Writer
}

func (b *basicWriter) WriteHeader(code int) {
	if !b.wroteHeader {
		b.code = code
		b.wroteHeader = true
		b.ResponseWriter.WriteHeader(code)
	}
}
func (b *basicWriter) Write(buf []byte) (int, error) {
	b.WriteHeader(http.StatusOK)
	n, err := b.ResponseWriter.Write(buf)
	if b.tee != nil {
		_, err2 := b.tee.Write(buf[:n])
		// Prefer errors generated by the proxied writer.
		if err == nil {
			err = err2
		}
	}
	b.bytes += n
	return n, err
}
func (b *basicWriter) maybeWriteHeader() {
	if !b.wroteHeader {
		b.WriteHeader(http.StatusOK)
	}
}
func (b *basicWriter) Status() int {
	return b.code
}
func (b *basicWriter) BytesWritten() int {
	return b.bytes
}
func (b *basicWriter) Tee(w io.Writer) {
	b.tee = w
}
func (b *basicWriter) Unwrap() http.ResponseWriter {
	return b.ResponseWriter
}

// fancyWriter is a writer that additionally satisfies http.CloseNotifier,
// http.Flusher, http.Hijacker, and io.ReaderFrom. It exists for the common case
// of wrapping the http.ResponseWriter that package http gives you, in order to
// make the proxied object support the full method set of the proxied object.
type fancyWriter struct {
	basicWriter
}

func (f *fancyWriter) CloseNotify() <-chan bool {
	cn := f.basicWriter.ResponseWriter.(http.CloseNotifier)
	return cn.CloseNotify()
}
func (f *fancyWriter) Flush() {
	fl := f.basicWriter.ResponseWriter.(http.Flusher)
	fl.Flush()
}
func (f *fancyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	hj := f.basicWriter.ResponseWriter.(http.Hijacker)
	return hj.Hijack()
}
func (f *fancyWriter) ReadFrom(r io.Reader) (int64, error) {
	if f.basicWriter.tee != nil {
		return io.Copy(&f.basicWriter, r)
	}
	rf := f.basicWriter.ResponseWriter.(io.ReaderFrom)
	f.basicWriter.maybeWriteHeader()
	return rf.ReadFrom(r)
}

var _ http.CloseNotifier = &fancyWriter{}
var _ http.Flusher = &fancyWriter{}
var _ http.Hijacker = &fancyWriter{}
var _ io.ReaderFrom = &fancyWriter{}
<|endoftext|>


<commit_before>// Package i18n implements a gettext based translation library with XLiff support
package i18n

import (
	"io/ioutil"
	"os"
	"strings"
)

type Catalog map[string]string
type LanguagesCatalog map[string]Catalog
type Parser func(fp *os.File) (Catalog, error)

func LoadCatalogs(translationsPath string, parser Parser) (LanguagesCatalog, error) {
	dirs, _ := ioutil.ReadDir(translationsPath)
	catalogs := make(map[string]Catalog)
	for _, fileInfo := range dirs {
		parts := strings.Split(fileInfo.Name(), ".")
		lang := parts[0]

		fp, err := os.Open(translationsPath + fileInfo.Name())
		if err != nil {
			return nil, err
		}
		defer fp.Close()

		catalog, err := parser(fp)
		if err != nil {
			return nil, err
		}

		catalogs[lang] = catalog
	}

	return catalogs, nil
}

func (catalog Catalog) String(message string) string {
	tmsg := catalog[message]
	if tmsg == "" {
		return message
	}
	return tmsg
}

func (catalog Catalog) StringN(msgid1, msgid2 string, n int) (tmsg string) {
	//
	// if n != 1 then it is plural
	//
	if n == 1 {
		tmsg = catalog[msgid1]
	} else {
		tmsg = catalog[msgid2]
	}
	if tmsg == "" {
		if n == 1 {
			tmsg = msgid1
		} else {
			tmsg = msgid2
		}
	}
	return tmsg
}
<commit_msg>Use filepath to join file paths<commit_after>// Package i18n implements a gettext based translation library with XLiff support
package i18n

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

type Catalog map[string]string
type LanguagesCatalog map[string]Catalog
type Parser func(fp *os.File) (Catalog, error)

func LoadCatalogs(translationsPath string, parser Parser) (LanguagesCatalog, error) {
	dirs, _ := ioutil.ReadDir(translationsPath)
	catalogs := make(map[string]Catalog)
	for _, fileInfo := range dirs {
		parts := strings.Split(fileInfo.Name(), ".")
		lang := parts[0]

		fp, err := os.Open(filepath.Join(translationsPath, fileInfo.Name()))
		if err != nil {
			return nil, err
		}
		defer fp.Close()

		catalog, err := parser(fp)
		if err != nil {
			return nil, err
		}

		catalogs[lang] = catalog
	}

	return catalogs, nil
}

func (catalog Catalog) String(message string) string {
	tmsg := catalog[message]
	if tmsg == "" {
		return message
	}
	return tmsg
}

func (catalog Catalog) StringN(msgid1, msgid2 string, n int) (tmsg string) {
	//
	// if n != 1 then it is plural
	//
	if n == 1 {
		tmsg = catalog[msgid1]
	} else {
		tmsg = catalog[msgid2]
	}
	if tmsg == "" {
		if n == 1 {
			tmsg = msgid1
		} else {
			tmsg = msgid2
		}
	}
	return tmsg
}
<|endoftext|>


<commit_before>// Copyright 2015 ISRG.  All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package sa

import (
	"bytes"
	"encoding/json"
	"fmt"
	"math"
	"net"
	"time"

	ct "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/google/certificate-transparency/go"
	jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"

	"github.com/letsencrypt/boulder/core"
)

var mediumBlobSize = int(math.Pow(2, 24))

type issuedNameModel struct {
	ID           int64     `db:"id"`
	ReversedName string    `db:"reversedName"`
	NotBefore    time.Time `db:"notBefore"`
	Serial       string    `db:"serial"`
}

// regModel is the description of a core.Registration in the database.
type regModel struct {
	ID        int64           `db:"id"`
	Key       []byte          `db:"jwk"`
	KeySHA256 string          `db:"jwk_sha256"`
	Contact   []*core.AcmeURL `db:"contact"`
	Agreement string          `db:"agreement"`
	// InitialIP is stored as sixteen binary bytes, regardless of whether it
	// represents a v4 or v6 IP address.
	InitialIP []byte    `db:"initialIp"`
	CreatedAt time.Time `db:"createdAt"`
	LockCol   int64
}

// challModel is the description of a core.Challenge in the database
//
// The Validation field is a stub; the column is only there for backward compatibility.
type challModel struct {
	ID              int64  `db:"id"`
	AuthorizationID string `db:"authorizationID"`

	Type             string          `db:"type"`
	Status           core.AcmeStatus `db:"status"`
	Error            []byte          `db:"error"`
	Validated        *time.Time      `db:"validated"`
	Token            string          `db:"token"`
	TLS              *bool           `db:"tls"`
	KeyAuthorization string          `db:"keyAuthorization"`
	ValidationRecord []byte          `db:"validationRecord"`
	AccountKey       []byte          `db:"accountKey"`

	LockCol int64
}

type sctModel struct {
	ID int64 `db:"id"`

	Version    uint8  `db:"sctVersion"`
	LogID      string `db:"logID"`
	Timestamp  uint64 `db:"timestamp"`
	Extensions []byte `db:"extensions"`
	Signature  []byte `db:"signature"`

	CertificateSerial string `db:"certificateSerial"`

	LockCol int64
}

func sctToModel(sct *ct.SignedCertificateTimestamp, serial string) (*sctModel, error) {
	sig, err := ct.MarshalDigitallySigned(sct.Signature)
	if err != nil {
		return nil, err
	}
	sm := &sctModel{
		CertificateSerial: serial,
		Version:           uint8(sct.SCTVersion),
		LogID:             sct.LogID.Base64String(),
		Timestamp:         sct.Timestamp,
		Extensions:        sct.Extensions,
		Signature:         sig,
	}
	fmt.Println("DOOPDOOP", sm.LogID)
	return sm, nil
}

func modelToSCT(sm *sctModel) (*ct.SignedCertificateTimestamp, error) {
	sig, err := ct.UnmarshalDigitallySigned(bytes.NewReader(sm.Signature))
	if err != nil {
		return nil, err
	}
	sct := &ct.SignedCertificateTimestamp{
		SCTVersion: ct.Version(sm.Version),
		Timestamp:  sm.Timestamp,
		Extensions: sm.Extensions,
		Signature:  *sig,
	}
	err = sct.LogID.FromBase64String(sm.LogID)
	if err != nil {
		return nil, err
	}
	return sct, nil
}

// newReg creates a reg model object from a core.Registration
func registrationToModel(r *core.Registration) (*regModel, error) {
	key, err := json.Marshal(r.Key)
	if err != nil {
		return nil, err
	}

	sha, err := core.KeyDigest(r.Key)
	if err != nil {
		return nil, err
	}
	if r.InitialIP == nil {
		return nil, fmt.Errorf("initialIP was nil")
	}
	rm := &regModel{
		ID:        r.ID,
		Key:       key,
		KeySHA256: sha,
		Contact:   r.Contact,
		Agreement: r.Agreement,
		InitialIP: []byte(r.InitialIP.To16()),
		CreatedAt: r.CreatedAt,
	}
	return rm, nil
}

func modelToRegistration(rm *regModel) (core.Registration, error) {
	k := &jose.JsonWebKey{}
	err := json.Unmarshal(rm.Key, k)
	if err != nil {
		err = fmt.Errorf("unable to unmarshal JsonWebKey in db: %s", err)
		return core.Registration{}, err
	}
	r := core.Registration{
		ID:        rm.ID,
		Key:       *k,
		Contact:   rm.Contact,
		Agreement: rm.Agreement,
		InitialIP: net.IP(rm.InitialIP),
		CreatedAt: rm.CreatedAt,
	}
	return r, nil
}

func challengeToModel(c *core.Challenge, authID string) (*challModel, error) {
	cm := challModel{
		ID:              c.ID,
		AuthorizationID: authID,
		Type:            c.Type,
		Status:          c.Status,
		Validated:       c.Validated,
		Token:           c.Token,
		TLS:             c.TLS,
	}
	if c.KeyAuthorization != nil {
		kaString := c.KeyAuthorization.String()
		if len(kaString) > 255 {
			return nil, fmt.Errorf("Key authorization is too large to store in the database")
		}
		cm.KeyAuthorization = kaString
	}
	if c.Error != nil {
		errJSON, err := json.Marshal(c.Error)
		if err != nil {
			return nil, err
		}
		if len(errJSON) > mediumBlobSize {
			return nil, fmt.Errorf("Error object is too large to store in the database")
		}
		cm.Error = errJSON
	}
	if len(c.ValidationRecord) > 0 {
		vrJSON, err := json.Marshal(c.ValidationRecord)
		if err != nil {
			return nil, err
		}
		if len(vrJSON) > mediumBlobSize {
			return nil, fmt.Errorf("Validation Record object is too large to store in the database")
		}
		cm.ValidationRecord = vrJSON
	}
	if c.AccountKey != nil {
		akJSON, err := json.Marshal(c.AccountKey)
		if err != nil {
			return nil, err
		}
		if len(akJSON) > mediumBlobSize {
			return nil, fmt.Errorf("Account key object is too large to store in the database")
		}
		cm.AccountKey = akJSON
	}
	return &cm, nil
}

func modelToChallenge(cm *challModel) (core.Challenge, error) {
	c := core.Challenge{
		ID:        cm.ID,
		Type:      cm.Type,
		Status:    cm.Status,
		Validated: cm.Validated,
		Token:     cm.Token,
		TLS:       cm.TLS,
	}
	if len(cm.KeyAuthorization) > 0 {
		ka, err := core.NewKeyAuthorizationFromString(cm.KeyAuthorization)
		if err != nil {
			return core.Challenge{}, err
		}
		c.KeyAuthorization = &ka
	}
	if len(cm.Error) > 0 {
		var problem core.ProblemDetails
		err := json.Unmarshal(cm.Error, &problem)
		if err != nil {
			return core.Challenge{}, err
		}
		c.Error = &problem
	}
	if len(cm.ValidationRecord) > 0 {
		var vr []core.ValidationRecord
		err := json.Unmarshal(cm.ValidationRecord, &vr)
		if err != nil {
			return core.Challenge{}, err
		}
		c.ValidationRecord = vr
	}
	if len(cm.AccountKey) > 0 {
		var ak jose.JsonWebKey
		err := json.Unmarshal(cm.AccountKey, &ak)
		if err != nil {
			return core.Challenge{}, err
		}
		c.AccountKey = &ak
	}
	return c, nil
}
<commit_msg>Remove dangling model functions<commit_after>// Copyright 2015 ISRG.  All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package sa

import (
	"encoding/json"
	"fmt"
	"math"
	"net"
	"time"

	jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
	"github.com/letsencrypt/boulder/core"
)

var mediumBlobSize = int(math.Pow(2, 24))

type issuedNameModel struct {
	ID           int64     `db:"id"`
	ReversedName string    `db:"reversedName"`
	NotBefore    time.Time `db:"notBefore"`
	Serial       string    `db:"serial"`
}

// regModel is the description of a core.Registration in the database.
type regModel struct {
	ID        int64           `db:"id"`
	Key       []byte          `db:"jwk"`
	KeySHA256 string          `db:"jwk_sha256"`
	Contact   []*core.AcmeURL `db:"contact"`
	Agreement string          `db:"agreement"`
	// InitialIP is stored as sixteen binary bytes, regardless of whether it
	// represents a v4 or v6 IP address.
	InitialIP []byte    `db:"initialIp"`
	CreatedAt time.Time `db:"createdAt"`
	LockCol   int64
}

// challModel is the description of a core.Challenge in the database
//
// The Validation field is a stub; the column is only there for backward compatibility.
type challModel struct {
	ID              int64  `db:"id"`
	AuthorizationID string `db:"authorizationID"`

	Type             string          `db:"type"`
	Status           core.AcmeStatus `db:"status"`
	Error            []byte          `db:"error"`
	Validated        *time.Time      `db:"validated"`
	Token            string          `db:"token"`
	TLS              *bool           `db:"tls"`
	KeyAuthorization string          `db:"keyAuthorization"`
	ValidationRecord []byte          `db:"validationRecord"`
	AccountKey       []byte          `db:"accountKey"`

	LockCol int64
}

// newReg creates a reg model object from a core.Registration
func registrationToModel(r *core.Registration) (*regModel, error) {
	key, err := json.Marshal(r.Key)
	if err != nil {
		return nil, err
	}

	sha, err := core.KeyDigest(r.Key)
	if err != nil {
		return nil, err
	}
	if r.InitialIP == nil {
		return nil, fmt.Errorf("initialIP was nil")
	}
	rm := &regModel{
		ID:        r.ID,
		Key:       key,
		KeySHA256: sha,
		Contact:   r.Contact,
		Agreement: r.Agreement,
		InitialIP: []byte(r.InitialIP.To16()),
		CreatedAt: r.CreatedAt,
	}
	return rm, nil
}

func modelToRegistration(rm *regModel) (core.Registration, error) {
	k := &jose.JsonWebKey{}
	err := json.Unmarshal(rm.Key, k)
	if err != nil {
		err = fmt.Errorf("unable to unmarshal JsonWebKey in db: %s", err)
		return core.Registration{}, err
	}
	r := core.Registration{
		ID:        rm.ID,
		Key:       *k,
		Contact:   rm.Contact,
		Agreement: rm.Agreement,
		InitialIP: net.IP(rm.InitialIP),
		CreatedAt: rm.CreatedAt,
	}
	return r, nil
}

func challengeToModel(c *core.Challenge, authID string) (*challModel, error) {
	cm := challModel{
		ID:              c.ID,
		AuthorizationID: authID,
		Type:            c.Type,
		Status:          c.Status,
		Validated:       c.Validated,
		Token:           c.Token,
		TLS:             c.TLS,
	}
	if c.KeyAuthorization != nil {
		kaString := c.KeyAuthorization.String()
		if len(kaString) > 255 {
			return nil, fmt.Errorf("Key authorization is too large to store in the database")
		}
		cm.KeyAuthorization = kaString
	}
	if c.Error != nil {
		errJSON, err := json.Marshal(c.Error)
		if err != nil {
			return nil, err
		}
		if len(errJSON) > mediumBlobSize {
			return nil, fmt.Errorf("Error object is too large to store in the database")
		}
		cm.Error = errJSON
	}
	if len(c.ValidationRecord) > 0 {
		vrJSON, err := json.Marshal(c.ValidationRecord)
		if err != nil {
			return nil, err
		}
		if len(vrJSON) > mediumBlobSize {
			return nil, fmt.Errorf("Validation Record object is too large to store in the database")
		}
		cm.ValidationRecord = vrJSON
	}
	if c.AccountKey != nil {
		akJSON, err := json.Marshal(c.AccountKey)
		if err != nil {
			return nil, err
		}
		if len(akJSON) > mediumBlobSize {
			return nil, fmt.Errorf("Account key object is too large to store in the database")
		}
		cm.AccountKey = akJSON
	}
	return &cm, nil
}

func modelToChallenge(cm *challModel) (core.Challenge, error) {
	c := core.Challenge{
		ID:        cm.ID,
		Type:      cm.Type,
		Status:    cm.Status,
		Validated: cm.Validated,
		Token:     cm.Token,
		TLS:       cm.TLS,
	}
	if len(cm.KeyAuthorization) > 0 {
		ka, err := core.NewKeyAuthorizationFromString(cm.KeyAuthorization)
		if err != nil {
			return core.Challenge{}, err
		}
		c.KeyAuthorization = &ka
	}
	if len(cm.Error) > 0 {
		var problem core.ProblemDetails
		err := json.Unmarshal(cm.Error, &problem)
		if err != nil {
			return core.Challenge{}, err
		}
		c.Error = &problem
	}
	if len(cm.ValidationRecord) > 0 {
		var vr []core.ValidationRecord
		err := json.Unmarshal(cm.ValidationRecord, &vr)
		if err != nil {
			return core.Challenge{}, err
		}
		c.ValidationRecord = vr
	}
	if len(cm.AccountKey) > 0 {
		var ak jose.JsonWebKey
		err := json.Unmarshal(cm.AccountKey, &ak)
		if err != nil {
			return core.Challenge{}, err
		}
		c.AccountKey = &ak
	}
	return c, nil
}
<|endoftext|>