<commit_before>package manet

import (
	"fmt"
	"net"
	"path/filepath"

	ma "github.com/multiformats/go-multiaddr"
)

var errIncorrectNetAddr = fmt.Errorf("incorrect network addr conversion")

// FromNetAddr converts a net.Addr type to a Multiaddr.
func FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
	return defaultCodecs.FromNetAddr(a)
}

// FromNetAddr converts a net.Addr to Multiaddress.
func (cm *CodecMap) FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
	if a == nil {
		return nil, fmt.Errorf("nil multiaddr")
	}
	p, err := cm.getAddrParser(a.Network())
	if err != nil {
		return nil, err
	}

	return p(a)
}

// ToNetAddr converts a Multiaddr to a net.Addr
// Must be ThinWaist. acceptable protocol stacks are:
// /ip{4,6}/{tcp, udp}
func ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
	return defaultCodecs.ToNetAddr(maddr)
}

// ToNetAddr converts a Multiaddress to a standard net.Addr.
func (cm *CodecMap) ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
	protos := maddr.Protocols()
	final := protos[len(protos)-1]

	p, err := cm.getMaddrParser(final.Name)
	if err != nil {
		return nil, err
	}

	return p(maddr)
}

func parseBasicNetMaddr(maddr ma.Multiaddr) (net.Addr, error) {
	network, host, err := DialArgs(maddr)
	if err != nil {
		return nil, err
	}

	switch network {
	case "tcp", "tcp4", "tcp6":
		return net.ResolveTCPAddr(network, host)
	case "udp", "udp4", "udp6":
		return net.ResolveUDPAddr(network, host)
	case "ip", "ip4", "ip6":
		return net.ResolveIPAddr(network, host)
	case "unix":
		return net.ResolveUnixAddr(network, host)
	}

	return nil, fmt.Errorf("network not supported: %s", network)
}

func FromIPAndZone(ip net.IP, zone string) (ma.Multiaddr, error) {
	switch {
	case ip.To4() != nil:
		return ma.NewComponent("ip4", ip.String())
	case ip.To16() != nil:
		ip6, err := ma.NewComponent("ip6", ip.String())
		if err != nil {
			return nil, err
		}
		if zone == "" {
			return ip6, nil
		} else {
			zone, err := ma.NewComponent("ip6zone", zone)
			if err != nil {
				return nil, err
			}
			return zone.Encapsulate(ip6), nil
		}
	default:
		return nil, errIncorrectNetAddr
	}
}

// FromIP converts a net.IP type to a Multiaddr.
func FromIP(ip net.IP) (ma.Multiaddr, error) {
	return FromIPAndZone(ip, "")
}

// DialArgs is a convenience function that returns network and address as
// expected by net.Dial. See https://godoc.org/net#Dial for an overview of
// possible return values (we do not support the unixpacket ones yet). Unix
// addresses do not, at present, compose.
func DialArgs(m ma.Multiaddr) (string, string, error) {
	var (
		zone, network, ip, port string
		err                     error
		hostname                bool
	)

	ma.ForEach(m, func(c ma.Component) bool {
		switch network {
		case "":
			switch c.Protocol().Code {
			case ma.P_IP6ZONE:
				if zone != "" {
					err = fmt.Errorf("%s has multiple zones", m)
					return false
				}
				zone = c.Value()
				return true
			case ma.P_IP6:
				network = "ip6"
				ip = c.Value()
				return true
			case ma.P_IP4:
				if zone != "" {
					err = fmt.Errorf("%s has ip4 with zone", m)
					return false
				}
				network = "ip4"
				ip = c.Value()
				return true
			case ma.P_DNS4:
				network = "ip4"
				hostname = true
				ip = c.Value()
				return true
			case ma.P_DNS6:
				network = "ip6"
				hostname = true
				ip = c.Value()
				return true
			case ma.P_UNIX:
				network = "unix"
				ip = c.Value()
				return false
			}
		case "ip4":
			switch c.Protocol().Code {
			case ma.P_UDP:
				network = "udp4"
			case ma.P_TCP:
				network = "tcp4"
			default:
				return false
			}
			port = c.Value()
		case "ip6":
			switch c.Protocol().Code {
			case ma.P_UDP:
				network = "udp6"
			case ma.P_TCP:
				network = "tcp6"
			default:
				return false
			}
			port = c.Value()
		}
		// Done.
		return false
	})
	if err != nil {
		return "", "", err
	}

	switch network {
	case "ip6":
		if zone != "" {
			ip += "%" + zone
		}
		fallthrough
	case "ip4":
		return network, ip, nil
	case "tcp4", "udp4":
		return network, ip + ":" + port, nil
	case "tcp6", "udp6":
		if zone != "" {
			ip += "%" + zone
		}
		if hostname {
			return network, ip + ":" + port, nil
		}
		return network, "[" + ip + "]" + ":" + port, nil
	case "unix":
		return network, ip, nil
	default:
		return "", "", fmt.Errorf("%s is not a 'thin waist' address", m)
	}
}

func parseTCPNetAddr(a net.Addr) (ma.Multiaddr, error) {
	ac, ok := a.(*net.TCPAddr)
	if !ok {
		return nil, errIncorrectNetAddr
	}

	// Get IP Addr
	ipm, err := FromIPAndZone(ac.IP, ac.Zone)
	if err != nil {
		return nil, errIncorrectNetAddr
	}

	// Get TCP Addr
	tcpm, err := ma.NewMultiaddr(fmt.Sprintf("/tcp/%d", ac.Port))
	if err != nil {
		return nil, errIncorrectNetAddr
	}

	// Encapsulate
	return ipm.Encapsulate(tcpm), nil
}

func parseUDPNetAddr(a net.Addr) (ma.Multiaddr, error) {
	ac, ok := a.(*net.UDPAddr)
	if !ok {
		return nil, errIncorrectNetAddr
	}

	// Get IP Addr
	ipm, err := FromIPAndZone(ac.IP, ac.Zone)
	if err != nil {
		return nil, errIncorrectNetAddr
	}

	// Get UDP Addr
	udpm, err := ma.NewMultiaddr(fmt.Sprintf("/udp/%d", ac.Port))
	if err != nil {
		return nil, errIncorrectNetAddr
	}

	// Encapsulate
	return ipm.Encapsulate(udpm), nil
}

func parseIPNetAddr(a net.Addr) (ma.Multiaddr, error) {
	ac, ok := a.(*net.IPAddr)
	if !ok {
		return nil, errIncorrectNetAddr
	}
	return FromIPAndZone(ac.IP, ac.Zone)
}

func parseIPPlusNetAddr(a net.Addr) (ma.Multiaddr, error) {
	ac, ok := a.(*net.IPNet)
	if !ok {
		return nil, errIncorrectNetAddr
	}
	return FromIP(ac.IP)
}

func parseUnixNetAddr(a net.Addr) (ma.Multiaddr, error) {
	ac, ok := a.(*net.UnixAddr)
	if !ok {
		return nil, errIncorrectNetAddr
	}
	cleaned := filepath.Clean(ac.Name)
	return ma.NewComponent("unix", cleaned)
}
<commit_msg>fix unix path handling on windows<commit_after>package manet

import (
	"fmt"
	"net"
	"path/filepath"

	ma "github.com/multiformats/go-multiaddr"
)

var errIncorrectNetAddr = fmt.Errorf("incorrect network addr conversion")

// FromNetAddr converts a net.Addr type to a Multiaddr.
func FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
	return defaultCodecs.FromNetAddr(a)
}

// FromNetAddr converts a net.Addr to Multiaddress.
func (cm *CodecMap) FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
	if a == nil {
		return nil, fmt.Errorf("nil multiaddr")
	}
	p, err := cm.getAddrParser(a.Network())
	if err != nil {
		return nil, err
	}

	return p(a)
}

// ToNetAddr converts a Multiaddr to a net.Addr
// Must be ThinWaist. acceptable protocol stacks are:
// /ip{4,6}/{tcp, udp}
func ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
	return defaultCodecs.ToNetAddr(maddr)
}

// ToNetAddr converts a Multiaddress to a standard net.Addr.
func (cm *CodecMap) ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
	protos := maddr.Protocols()
	final := protos[len(protos)-1]

	p, err := cm.getMaddrParser(final.Name)
	if err != nil {
		return nil, err
	}

	return p(maddr)
}

func parseBasicNetMaddr(maddr ma.Multiaddr) (net.Addr, error) {
	network, host, err := DialArgs(maddr)
	if err != nil {
		return nil, err
	}

	switch network {
	case "tcp", "tcp4", "tcp6":
		return net.ResolveTCPAddr(network, host)
	case "udp", "udp4", "udp6":
		return net.ResolveUDPAddr(network, host)
	case "ip", "ip4", "ip6":
		return net.ResolveIPAddr(network, host)
	case "unix":
		return net.ResolveUnixAddr(network, host)
	}

	return nil, fmt.Errorf("network not supported: %s", network)
}

func FromIPAndZone(ip net.IP, zone string) (ma.Multiaddr, error) {
	switch {
	case ip.To4() != nil:
		return ma.NewComponent("ip4", ip.String())
	case ip.To16() != nil:
		ip6, err := ma.NewComponent("ip6", ip.String())
		if err != nil {
			return nil, err
		}
		if zone == "" {
			return ip6, nil
		} else {
			zone, err := ma.NewComponent("ip6zone", zone)
			if err != nil {
				return nil, err
			}
			return zone.Encapsulate(ip6), nil
		}
	default:
		return nil, errIncorrectNetAddr
	}
}

// FromIP converts a net.IP type to a Multiaddr.
func FromIP(ip net.IP) (ma.Multiaddr, error) {
	return FromIPAndZone(ip, "")
}

// DialArgs is a convenience function that returns network and address as
// expected by net.Dial. See https://godoc.org/net#Dial for an overview of
// possible return values (we do not support the unixpacket ones yet). Unix
// addresses do not, at present, compose.
func DialArgs(m ma.Multiaddr) (string, string, error) {
	var (
		zone, network, ip, port string
		err                     error
		hostname                bool
	)

	ma.ForEach(m, func(c ma.Component) bool {
		switch network {
		case "":
			switch c.Protocol().Code {
			case ma.P_IP6ZONE:
				if zone != "" {
					err = fmt.Errorf("%s has multiple zones", m)
					return false
				}
				zone = c.Value()
				return true
			case ma.P_IP6:
				network = "ip6"
				ip = c.Value()
				return true
			case ma.P_IP4:
				if zone != "" {
					err = fmt.Errorf("%s has ip4 with zone", m)
					return false
				}
				network = "ip4"
				ip = c.Value()
				return true
			case ma.P_DNS4:
				network = "ip4"
				hostname = true
				ip = c.Value()
				return true
			case ma.P_DNS6:
				network = "ip6"
				hostname = true
				ip = c.Value()
				return true
			case ma.P_UNIX:
				network = "unix"
				ip = c.Value()
				return false
			}
		case "ip4":
			switch c.Protocol().Code {
			case ma.P_UDP:
				network = "udp4"
			case ma.P_TCP:
				network = "tcp4"
			default:
				return false
			}
			port = c.Value()
		case "ip6":
			switch c.Protocol().Code {
			case ma.P_UDP:
				network = "udp6"
			case ma.P_TCP:
				network = "tcp6"
			default:
				return false
			}
			port = c.Value()
		}
		// Done.
		return false
	})
	if err != nil {
		return "", "", err
	}

	switch network {
	case "ip6":
		if zone != "" {
			ip += "%" + zone
		}
		fallthrough
	case "ip4":
		return network, ip, nil
	case "tcp4", "udp4":
		return network, ip + ":" + port, nil
	case "tcp6", "udp6":
		if zone != "" {
			ip += "%" + zone
		}
		if hostname {
			return network, ip + ":" + port, nil
		}
		return network, "[" + ip + "]" + ":" + port, nil
	case "unix":
		return network, filepath.FromSlash(ip), nil
	default:
		return "", "", fmt.Errorf("%s is not a 'thin waist' address", m)
	}
}

func parseTCPNetAddr(a net.Addr) (ma.Multiaddr, error) {
	ac, ok := a.(*net.TCPAddr)
	if !ok {
		return nil, errIncorrectNetAddr
	}

	// Get IP Addr
	ipm, err := FromIPAndZone(ac.IP, ac.Zone)
	if err != nil {
		return nil, errIncorrectNetAddr
	}

	// Get TCP Addr
	tcpm, err := ma.NewMultiaddr(fmt.Sprintf("/tcp/%d", ac.Port))
	if err != nil {
		return nil, errIncorrectNetAddr
	}

	// Encapsulate
	return ipm.Encapsulate(tcpm), nil
}

func parseUDPNetAddr(a net.Addr) (ma.Multiaddr, error) {
	ac, ok := a.(*net.UDPAddr)
	if !ok {
		return nil, errIncorrectNetAddr
	}

	// Get IP Addr
	ipm, err := FromIPAndZone(ac.IP, ac.Zone)
	if err != nil {
		return nil, errIncorrectNetAddr
	}

	// Get UDP Addr
	udpm, err := ma.NewMultiaddr(fmt.Sprintf("/udp/%d", ac.Port))
	if err != nil {
		return nil, errIncorrectNetAddr
	}

	// Encapsulate
	return ipm.Encapsulate(udpm), nil
}

func parseIPNetAddr(a net.Addr) (ma.Multiaddr, error) {
	ac, ok := a.(*net.IPAddr)
	if !ok {
		return nil, errIncorrectNetAddr
	}
	return FromIPAndZone(ac.IP, ac.Zone)
}

func parseIPPlusNetAddr(a net.Addr) (ma.Multiaddr, error) {
	ac, ok := a.(*net.IPNet)
	if !ok {
		return nil, errIncorrectNetAddr
	}
	return FromIP(ac.IP)
}

func parseUnixNetAddr(a net.Addr) (ma.Multiaddr, error) {
	ac, ok := a.(*net.UnixAddr)
	if !ok {
		return nil, errIncorrectNetAddr
	}

	return ma.NewComponent("unix", filepath.ToSlash(ac.Name))
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package upgrader

import (
	"fmt"

	"launchpad.net/juju-core/state/api/base"
	"launchpad.net/juju-core/state/api/params"
	"launchpad.net/juju-core/state/api/watcher"
	"launchpad.net/juju-core/tools"
	"launchpad.net/juju-core/utils"
	"launchpad.net/juju-core/version"
)

// State provides access to an upgrader worker's view of the state.
type State struct {
	caller base.Caller
}

// NewState returns a version of the state that provides functionality
// required by the upgrader worker.
func NewState(caller base.Caller) *State {
	return &State{caller}
}

// SetVersion sets the tools version associated with the entity with
// the given tag, which must be the tag of the entity that the
// upgrader is running on behalf of.
func (st *State) SetVersion(tag string, v version.Binary) error {
	var results params.ErrorResults
	args := params.EntitiesVersion{
		AgentTools: []params.EntityVersion{{
			Tag:   tag,
			Tools: &params.Version{v},
		}},
	}
	err := st.caller.Call("Upgrader", "", "SetTools", args, &results)
	if err != nil {
		// TODO: Not directly tested
		return err
	}
	return results.OneError()
}

func (st *State) DesiredVersion(tag string) (version.Number, error) {
	var results params.VersionResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: tag}},
	}
	err := st.caller.Call("Upgrader", "", "DesiredVersion", args, &results)
	if err != nil {
		// TODO: Not directly tested
		return version.Number{}, err
	}
	if len(results.Results) != 1 {
		// TODO: Not directly tested
		return version.Number{}, fmt.Errorf("expected one result, got %d", len(results.Results))
	}
	result := results.Results[0]
	if err := result.Error; err != nil {
		return version.Number{}, err
	}
	if result.Version == nil {
		// TODO: Not directly tested
		return version.Number{}, fmt.Errorf("received no error, but got a nil Version")
	}
	return *result.Version, nil
}

// Tools returns the agent tools that should run on the given entity,
// along with a flag whether to disable SSL hostname verification.
func (st *State) Tools(tag string) (*tools.Tools, utils.SSLHostnameVerification, error) {
	var results params.ToolsResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: tag}},
	}
	err := st.caller.Call("Upgrader", "", "Tools", args, &results)
	if err != nil {
		// TODO: Not directly tested
		return nil, false, err
	}
	if len(results.Results) != 1 {
		// TODO: Not directly tested
		return nil, false, fmt.Errorf("expected one result, got %d", len(results.Results))
	}
	result := results.Results[0]
	if err := result.Error; err != nil {
		return nil, false, err
	}
	hostnameVerification := utils.VerifySSLHostnames
	if result.DisableSSLHostnameVerification {
		hostnameVerification = utils.NoVerifySSLHostnames
	}
	return result.Tools, hostnameVerification, nil
}

func (st *State) WatchAPIVersion(agentTag string) (watcher.NotifyWatcher, error) {
	var results params.NotifyWatchResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: agentTag}},
	}
	err := st.caller.Call("Upgrader", "", "WatchAPIVersion", args, &results)
	if err != nil {
		// TODO: Not directly tested
		return nil, err
	}
	if len(results.Results) != 1 {
		// TODO: Not directly tested
		return nil, fmt.Errorf("expected one result, got %d", len(results.Results))
	}
	result := results.Results[0]
	if result.Error != nil {
		//  TODO: Not directly tested
		return nil, result.Error
	}
	w := watcher.NewNotifyWatcher(st.caller, result)
	return w, nil
}
<commit_msg>api/upgrader<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package upgrader

import (
	"fmt"

	"launchpad.net/juju-core/state/api/base"
	"launchpad.net/juju-core/state/api/params"
	"launchpad.net/juju-core/state/api/watcher"
	"launchpad.net/juju-core/tools"
	"launchpad.net/juju-core/utils"
	"launchpad.net/juju-core/version"
)

const upgraderFacade = "Upgrader"

// State provides access to an upgrader worker's view of the state.
type State struct {
	caller base.Caller
}

func (st *State) call(method string, params, result interface{}) error {
	return st.caller.Call(upgraderFacade, "", method, params, result)
}

// NewState returns a version of the state that provides functionality
// required by the upgrader worker.
func NewState(caller base.Caller) *State {
	return &State{caller}
}

// SetVersion sets the tools version associated with the entity with
// the given tag, which must be the tag of the entity that the
// upgrader is running on behalf of.
func (st *State) SetVersion(tag string, v version.Binary) error {
	var results params.ErrorResults
	args := params.EntitiesVersion{
		AgentTools: []params.EntityVersion{{
			Tag:   tag,
			Tools: &params.Version{v},
		}},
	}
	err := st.call("SetTools", args, &results)
	if err != nil {
		// TODO: Not directly tested
		return err
	}
	return results.OneError()
}

func (st *State) DesiredVersion(tag string) (version.Number, error) {
	var results params.VersionResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: tag}},
	}
	err := st.call("DesiredVersion", args, &results)
	if err != nil {
		// TODO: Not directly tested
		return version.Number{}, err
	}
	if len(results.Results) != 1 {
		// TODO: Not directly tested
		return version.Number{}, fmt.Errorf("expected one result, got %d", len(results.Results))
	}
	result := results.Results[0]
	if err := result.Error; err != nil {
		return version.Number{}, err
	}
	if result.Version == nil {
		// TODO: Not directly tested
		return version.Number{}, fmt.Errorf("received no error, but got a nil Version")
	}
	return *result.Version, nil
}

// Tools returns the agent tools that should run on the given entity,
// along with a flag whether to disable SSL hostname verification.
func (st *State) Tools(tag string) (*tools.Tools, utils.SSLHostnameVerification, error) {
	var results params.ToolsResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: tag}},
	}
	err := st.call("Tools", args, &results)
	if err != nil {
		// TODO: Not directly tested
		return nil, false, err
	}
	if len(results.Results) != 1 {
		// TODO: Not directly tested
		return nil, false, fmt.Errorf("expected one result, got %d", len(results.Results))
	}
	result := results.Results[0]
	if err := result.Error; err != nil {
		return nil, false, err
	}
	hostnameVerification := utils.VerifySSLHostnames
	if result.DisableSSLHostnameVerification {
		hostnameVerification = utils.NoVerifySSLHostnames
	}
	return result.Tools, hostnameVerification, nil
}

func (st *State) WatchAPIVersion(agentTag string) (watcher.NotifyWatcher, error) {
	var results params.NotifyWatchResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: agentTag}},
	}
	err := st.call("WatchAPIVersion", args, &results)
	if err != nil {
		// TODO: Not directly tested
		return nil, err
	}
	if len(results.Results) != 1 {
		// TODO: Not directly tested
		return nil, fmt.Errorf("expected one result, got %d", len(results.Results))
	}
	result := results.Results[0]
	if result.Error != nil {
		//  TODO: Not directly tested
		return nil, result.Error
	}
	w := watcher.NewNotifyWatcher(st.caller, result)
	return w, nil
}
<|endoftext|>


<commit_before>package renderweb

import (
	"fmt"
	"strings"

	"github.com/rs/xhandler"
	"github.com/rs/xmux"
)

// Route - Web route.
type Route struct {
	Path   string `json:"path,omitempty" yaml:"path,omitempty"`
	Method string `json:"method,omitempty" yaml:"method,omitempty"`
}

// Routes - Routes map.
type Routes map[Route]*Handler

// String - Returns string representation of a route.
func (route Route) String() string {
	return strings.Join([]string{route.Method, route.Path}, " ")
}

// Construct - Constructs http router.
func (routes Routes) Construct(options ...Option) (xhandler.HandlerC, error) {
	// Create new router
	mux := xmux.New()

	// Bind all routes handlers
	for route, handler := range routes {
		// Construct handler
		h, err := handler.Construct(options...)
		if err != nil {
			return nil, fmt.Errorf("%q: %v", route, err)
		}

		// Bind route handler
		mux.HandleC(route.Method, route.Path, h)
	}

	// Return handler
	return mux, nil
}
<commit_msg>renderweb: routes tracing<commit_after>package renderweb

import (
	"fmt"
	"net/http"
	"strings"

	"golang.org/x/net/context"
	"golang.org/x/net/trace"

	"github.com/rs/xhandler"
	"github.com/rs/xmux"
)

// Route - Web route.
type Route struct {
	Path   string `json:"path,omitempty" yaml:"path,omitempty"`
	Method string `json:"method,omitempty" yaml:"method,omitempty"`
}

// Routes - Routes map.
type Routes map[Route]*Handler

// String - Returns string representation of a route.
func (route Route) String() string {
	return strings.Join([]string{route.Method, route.Path}, " ")
}

// Construct - Constructs http router.
func (routes Routes) Construct(options ...Option) (xhandler.HandlerC, error) {
	// Create new router
	mux := xmux.New()

	tracing := tracingEnabled(options...)

	// Bind all routes handlers
	for route, handler := range routes {
		// Construct handler
		h, err := handler.Construct(options...)
		if err != nil {
			return nil, fmt.Errorf("%q: %v", route, err)
		}

		if tracing {
			h = routeTracing(route, h)
		}

		// Bind route handler
		mux.HandleC(route.Method, route.Path, h)
	}

	// Return handler
	return mux, nil
}

func routeTracing(route Route, handler xhandler.HandlerC) xhandler.HandlerC {
	rs := route.String()
	return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		tr := trace.New(rs, fmt.Sprintf("%s %s", r.Method, r.URL.Path))
		ctx = trace.NewContext(ctx, tr)
		handler.ServeHTTPC(ctx, w, r)
		tr.Finish()
	})
}
<|endoftext|>


<commit_before>// Copyright 2014 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 core

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"crypto/x509"
	"encoding/asn1"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"math/big"
	"net/url"
	"strings"

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

// Package Variables Variables

// BuildID is set by the compiler (using -ldflags "-X core.BuildID $(git rev-parse --short HEAD)")
// and is used by GetBuildID
var BuildID string

// BuildHost is set by the compiler and is used by GetBuildHost
var BuildHost string

// BuildTime is set by the compiler and is used by GetBuildTime
var BuildTime string

// Errors

// InternalServerError indicates that something has gone wrong unrelated to the
// user's input, and will be considered by the Load Balancer as an indication
// that this Boulder instance may be malfunctioning. Minimally, returning this
// will cause an error page to be generated at the CDN/LB for the client.
// Consequently, you should only use this error when Boulder's internal
// constraints have been violated.
type InternalServerError string

// NotSupportedError indicates a method is not yet supported
type NotSupportedError string

// MalformedRequestError indicates the user data was improper
type MalformedRequestError string

// UnauthorizedError indicates the user did not satisfactorily prove identity
type UnauthorizedError string

// NotFoundError indicates the destination was unknown. Whoa oh oh ohhh.
type NotFoundError string

// LengthRequiredError indicates a POST was sent with no Content-Length.
type LengthRequiredError string

// SyntaxError indicates the user improperly formatted their data.
type SyntaxError string

// SignatureValidationError indicates that the user's signature could not
// be verified, either through adversarial activity, or misconfiguration of
// the user client.
type SignatureValidationError string

// CertificateIssuanceError indicates the certificate failed to be issued
// for some reason.
type CertificateIssuanceError string

// NoSuchRegistrationError indicates that a registration could not be found.
type NoSuchRegistrationError string

// RateLimitedError indicates the user has hit a rate limit
type RateLimitedError string

// TooManyRPCRequestsError indicates an RPC server has hit it's concurrent request
// limit
type TooManyRPCRequestsError string

func (e InternalServerError) Error() string      { return string(e) }
func (e NotSupportedError) Error() string        { return string(e) }
func (e MalformedRequestError) Error() string    { return string(e) }
func (e UnauthorizedError) Error() string        { return string(e) }
func (e NotFoundError) Error() string            { return string(e) }
func (e LengthRequiredError) Error() string      { return string(e) }
func (e SyntaxError) Error() string              { return string(e) }
func (e SignatureValidationError) Error() string { return string(e) }
func (e CertificateIssuanceError) Error() string { return string(e) }
func (e NoSuchRegistrationError) Error() string  { return string(e) }
func (e RateLimitedError) Error() string         { return string(e) }
func (e TooManyRPCRequestsError) Error() string  { return string(e) }

// Base64 functions

func pad(x string) string {
	switch len(x) % 4 {
	case 2:
		return x + "=="
	case 3:
		return x + "="
	}
	return x
}

func unpad(x string) string {
	return strings.Replace(x, "=", "", -1)
}

// B64enc encodes a byte array as unpadded, URL-safe Base64
func B64enc(x []byte) string {
	return unpad(base64.URLEncoding.EncodeToString(x))
}

// B64dec decodes a byte array from unpadded, URL-safe Base64
func B64dec(x string) ([]byte, error) {
	return base64.URLEncoding.DecodeString(pad(x))
}

// Random stuff

// RandomString returns a randomly generated string of the requested length.
func RandomString(byteLength int) string {
	b := make([]byte, byteLength)
	_, err := io.ReadFull(rand.Reader, b)
	if err != nil {
		ohdear := "RandomString entropy failure? " + err.Error()
		logger := blog.GetAuditLogger()
		logger.EmergencyExit(ohdear)
	}
	return B64enc(b)
}

// NewToken produces a random string for Challenges, etc.
func NewToken() string {
	return RandomString(32)
}

// Fingerprints

// Fingerprint256 produces an unpadded, URL-safe Base64-encoded SHA256 digest
// of the data.
func Fingerprint256(data []byte) string {
	d := sha256.New()
	_, _ = d.Write(data) // Never returns an error
	return B64enc(d.Sum(nil))
}

// KeyDigest produces a padded, standard Base64-encoded SHA256 digest of a
// provided public key.
func KeyDigest(key crypto.PublicKey) (string, error) {
	switch t := key.(type) {
	case *jose.JsonWebKey:
		if t == nil {
			return "", fmt.Errorf("Cannot compute digest of nil key")
		}
		return KeyDigest(t.Key)
	case jose.JsonWebKey:
		return KeyDigest(t.Key)
	default:
		keyDER, err := x509.MarshalPKIXPublicKey(key)
		if err != nil {
			logger := blog.GetAuditLogger()
			logger.Debug(fmt.Sprintf("Problem marshaling public key: %s", err))
			return "", err
		}
		spkiDigest := sha256.Sum256(keyDER)
		return base64.StdEncoding.EncodeToString(spkiDigest[0:32]), nil
	}
}

// KeyDigestEquals determines whether two public keys have the same digest.
func KeyDigestEquals(j, k crypto.PublicKey) bool {
	digestJ, errJ := KeyDigest(j)
	digestK, errK := KeyDigest(k)
	// Keys that don't have a valid digest (due to marshalling problems)
	// are never equal. So, e.g. nil keys are not equal.
	if errJ != nil || errK != nil {
		return false
	}
	return digestJ == digestK
}

// AcmeURL is a URL that automatically marshal/unmarshal to JSON strings
type AcmeURL url.URL

func ParseAcmeURL(s string) (*AcmeURL, error) {
	u, err := url.Parse(s)
	if err != nil {
		return nil, err
	}
	return (*AcmeURL)(u), nil
}

func (u *AcmeURL) String() string {
	uu := (*url.URL)(u)
	return uu.String()
}

// PathSegments splits an AcmeURL into segments on the '/' characters
func (u *AcmeURL) PathSegments() (segments []string) {
	segments = strings.Split(u.Path, "/")
	if len(segments) > 0 && len(segments[0]) == 0 {
		segments = segments[1:]
	}
	return
}

// MarshalJSON encodes an AcmeURL for transfer
func (u *AcmeURL) MarshalJSON() ([]byte, error) {
	return json.Marshal(u.String())
}

// UnmarshalJSON decodes an AcmeURL from transfer
func (u *AcmeURL) UnmarshalJSON(data []byte) error {
	var str string
	if err := json.Unmarshal(data, &str); err != nil {
		return err
	}

	uu, err := url.Parse(str)
	*u = AcmeURL(*uu)
	return err
}

// VerifyCSR verifies that a Certificate Signature Request is well-formed.
//
// Note: this is the missing CertificateRequest.Verify() method
func VerifyCSR(csr *x509.CertificateRequest) error {
	// Compute the hash of the TBSCertificateRequest
	var hashID crypto.Hash
	var hash hash.Hash
	switch csr.SignatureAlgorithm {
	case x509.SHA1WithRSA:
		fallthrough
	case x509.ECDSAWithSHA1:
		hashID = crypto.SHA1
		hash = sha1.New()
	case x509.SHA256WithRSA:
		fallthrough
	case x509.ECDSAWithSHA256:
		hashID = crypto.SHA256
		hash = sha256.New()
	case x509.SHA384WithRSA:
		fallthrough
	case x509.ECDSAWithSHA384:
		hashID = crypto.SHA384
		hash = sha512.New384()
	case x509.SHA512WithRSA:
		fallthrough
	case x509.ECDSAWithSHA512:
		hashID = crypto.SHA512
		hash = sha512.New()
	default:
		return errors.New("Unsupported CSR signing algorithm")
	}
	_, _ = hash.Write(csr.RawTBSCertificateRequest) // Never returns an error
	inputHash := hash.Sum(nil)

	// Verify the signature using the public key in the CSR
	switch csr.SignatureAlgorithm {
	case x509.SHA1WithRSA:
		fallthrough
	case x509.SHA256WithRSA:
		fallthrough
	case x509.SHA384WithRSA:
		fallthrough
	case x509.SHA512WithRSA:
		rsaKey := csr.PublicKey.(*rsa.PublicKey)
		return rsa.VerifyPKCS1v15(rsaKey, hashID, inputHash, csr.Signature)
	case x509.ECDSAWithSHA1:
		fallthrough
	case x509.ECDSAWithSHA256:
		fallthrough
	case x509.ECDSAWithSHA384:
		fallthrough
	case x509.ECDSAWithSHA512:
		ecKey := csr.PublicKey.(*ecdsa.PublicKey)

		var sig struct{ R, S *big.Int }
		_, err := asn1.Unmarshal(csr.Signature, &sig)
		if err != nil {
			return err
		}

		if ecdsa.Verify(ecKey, inputHash, sig.R, sig.S) {
			return nil
		}

		return errors.New("Invalid ECDSA signature on CSR")
	}

	return errors.New("Unsupported CSR signing algorithm")
}

// SerialToString converts a certificate serial number (big.Int) to a String
// consistently.
func SerialToString(serial *big.Int) string {
	return fmt.Sprintf("%036x", serial)
}

// StringToSerial converts a string into a certificate serial number (big.Int)
// consistently.
func StringToSerial(serial string) (*big.Int, error) {
	var serialNum big.Int
	if !ValidSerial(serial) {
		return &serialNum, errors.New("Invalid serial number")
	}
	_, err := fmt.Sscanf(serial, "%036x", &serialNum)
	return &serialNum, err
}

func ValidSerial(serial string) bool {
	// Originally, serial numbers were 32 hex characters long. We later increased
	// them to 36, but we allow the shorter ones because they exist in some
	// production databases.
	if len(serial) < 32 && len(serial) > 36 {
		return false
	}
	_, err := hex.DecodeString(serial)
	if err != nil {
		return false
	}
	return true
}

// GetBuildID identifies what build is running.
func GetBuildID() (retID string) {
	retID = BuildID
	if retID == "" {
		retID = "Unspecified"
	}
	return
}

// GetBuildTime identifies when this build was made
func GetBuildTime() (retID string) {
	retID = BuildTime
	if retID == "" {
		retID = "Unspecified"
	}
	return
}

// GetBuildHost identifies the building host
func GetBuildHost() (retID string) {
	retID = BuildHost
	if retID == "" {
		retID = "Unspecified"
	}
	return
}

// UniqueNames returns the set of all unique names in the input.
func UniqueNames(names []string) (unique []string) {
	nameMap := make(map[string]int, len(names))
	for _, name := range names {
		nameMap[name] = 1
	}

	unique = make([]string, 0, len(nameMap))
	for name := range nameMap {
		unique = append(unique, name)
	}
	return
}

// LoadCertBundle loads a PEM bundle of certificates from disk
func LoadCertBundle(filename string) ([]*x509.Certificate, error) {
	bundleBytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	var bundle []*x509.Certificate
	var block *pem.Block
	rest := bundleBytes
	for {
		block, rest = pem.Decode(rest)
		if block == nil {
			break
		}
		if block.Type != "CERTIFICATE" {
			return nil, fmt.Errorf("Block has invalid type: %s", block.Type)
		}
		cert, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			return nil, err
		}
		bundle = append(bundle, cert)
	}

	if len(bundle) == 0 {
		return nil, fmt.Errorf("Bundle doesn't contain any certificates")
	}

	return bundle, nil
}

// LoadCert loads a PEM certificate specified by filename or returns a error
func LoadCert(filename string) (cert *x509.Certificate, err error) {
	certPEM, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	block, _ := pem.Decode(certPEM)
	if block == nil {
		return nil, fmt.Errorf("No data in cert PEM file %s", filename)
	}
	cert, err = x509.ParseCertificate(block.Bytes)
	return
}
<commit_msg>remove some allocations from B64enc codepath<commit_after>// Copyright 2014 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 core

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"crypto/x509"
	"encoding/asn1"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"math/big"
	"net/url"
	"strings"

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

// Package Variables Variables

// BuildID is set by the compiler (using -ldflags "-X core.BuildID $(git rev-parse --short HEAD)")
// and is used by GetBuildID
var BuildID string

// BuildHost is set by the compiler and is used by GetBuildHost
var BuildHost string

// BuildTime is set by the compiler and is used by GetBuildTime
var BuildTime string

// Errors

// InternalServerError indicates that something has gone wrong unrelated to the
// user's input, and will be considered by the Load Balancer as an indication
// that this Boulder instance may be malfunctioning. Minimally, returning this
// will cause an error page to be generated at the CDN/LB for the client.
// Consequently, you should only use this error when Boulder's internal
// constraints have been violated.
type InternalServerError string

// NotSupportedError indicates a method is not yet supported
type NotSupportedError string

// MalformedRequestError indicates the user data was improper
type MalformedRequestError string

// UnauthorizedError indicates the user did not satisfactorily prove identity
type UnauthorizedError string

// NotFoundError indicates the destination was unknown. Whoa oh oh ohhh.
type NotFoundError string

// LengthRequiredError indicates a POST was sent with no Content-Length.
type LengthRequiredError string

// SyntaxError indicates the user improperly formatted their data.
type SyntaxError string

// SignatureValidationError indicates that the user's signature could not
// be verified, either through adversarial activity, or misconfiguration of
// the user client.
type SignatureValidationError string

// CertificateIssuanceError indicates the certificate failed to be issued
// for some reason.
type CertificateIssuanceError string

// NoSuchRegistrationError indicates that a registration could not be found.
type NoSuchRegistrationError string

// RateLimitedError indicates the user has hit a rate limit
type RateLimitedError string

// TooManyRPCRequestsError indicates an RPC server has hit it's concurrent request
// limit
type TooManyRPCRequestsError string

func (e InternalServerError) Error() string      { return string(e) }
func (e NotSupportedError) Error() string        { return string(e) }
func (e MalformedRequestError) Error() string    { return string(e) }
func (e UnauthorizedError) Error() string        { return string(e) }
func (e NotFoundError) Error() string            { return string(e) }
func (e LengthRequiredError) Error() string      { return string(e) }
func (e SyntaxError) Error() string              { return string(e) }
func (e SignatureValidationError) Error() string { return string(e) }
func (e CertificateIssuanceError) Error() string { return string(e) }
func (e NoSuchRegistrationError) Error() string  { return string(e) }
func (e RateLimitedError) Error() string         { return string(e) }
func (e TooManyRPCRequestsError) Error() string  { return string(e) }

// Base64 functions

func pad(x string) string {
	switch len(x) % 4 {
	case 2:
		return x + "=="
	case 3:
		return x + "="
	}
	return x
}

func unpad(x string) string {
	end := len(x)
	for end != 0 && x[end-1] == '=' {
		end--
	}
	return x[:end]
}

// B64enc encodes a byte array as unpadded, URL-safe Base64
func B64enc(x []byte) string {
	return unpad(base64.URLEncoding.EncodeToString(x))
}

// B64dec decodes a byte array from unpadded, URL-safe Base64
func B64dec(x string) ([]byte, error) {
	return base64.URLEncoding.DecodeString(pad(x))
}

// Random stuff

// RandomString returns a randomly generated string of the requested length.
func RandomString(byteLength int) string {
	b := make([]byte, byteLength)
	_, err := io.ReadFull(rand.Reader, b)
	if err != nil {
		ohdear := "RandomString entropy failure? " + err.Error()
		logger := blog.GetAuditLogger()
		logger.EmergencyExit(ohdear)
	}
	return B64enc(b)
}

// NewToken produces a random string for Challenges, etc.
func NewToken() string {
	return RandomString(32)
}

// Fingerprints

// Fingerprint256 produces an unpadded, URL-safe Base64-encoded SHA256 digest
// of the data.
func Fingerprint256(data []byte) string {
	d := sha256.New()
	_, _ = d.Write(data) // Never returns an error
	return B64enc(d.Sum(nil))
}

// KeyDigest produces a padded, standard Base64-encoded SHA256 digest of a
// provided public key.
func KeyDigest(key crypto.PublicKey) (string, error) {
	switch t := key.(type) {
	case *jose.JsonWebKey:
		if t == nil {
			return "", fmt.Errorf("Cannot compute digest of nil key")
		}
		return KeyDigest(t.Key)
	case jose.JsonWebKey:
		return KeyDigest(t.Key)
	default:
		keyDER, err := x509.MarshalPKIXPublicKey(key)
		if err != nil {
			logger := blog.GetAuditLogger()
			logger.Debug(fmt.Sprintf("Problem marshaling public key: %s", err))
			return "", err
		}
		spkiDigest := sha256.Sum256(keyDER)
		return base64.StdEncoding.EncodeToString(spkiDigest[0:32]), nil
	}
}

// KeyDigestEquals determines whether two public keys have the same digest.
func KeyDigestEquals(j, k crypto.PublicKey) bool {
	digestJ, errJ := KeyDigest(j)
	digestK, errK := KeyDigest(k)
	// Keys that don't have a valid digest (due to marshalling problems)
	// are never equal. So, e.g. nil keys are not equal.
	if errJ != nil || errK != nil {
		return false
	}
	return digestJ == digestK
}

// AcmeURL is a URL that automatically marshal/unmarshal to JSON strings
type AcmeURL url.URL

func ParseAcmeURL(s string) (*AcmeURL, error) {
	u, err := url.Parse(s)
	if err != nil {
		return nil, err
	}
	return (*AcmeURL)(u), nil
}

func (u *AcmeURL) String() string {
	uu := (*url.URL)(u)
	return uu.String()
}

// PathSegments splits an AcmeURL into segments on the '/' characters
func (u *AcmeURL) PathSegments() (segments []string) {
	segments = strings.Split(u.Path, "/")
	if len(segments) > 0 && len(segments[0]) == 0 {
		segments = segments[1:]
	}
	return
}

// MarshalJSON encodes an AcmeURL for transfer
func (u *AcmeURL) MarshalJSON() ([]byte, error) {
	return json.Marshal(u.String())
}

// UnmarshalJSON decodes an AcmeURL from transfer
func (u *AcmeURL) UnmarshalJSON(data []byte) error {
	var str string
	if err := json.Unmarshal(data, &str); err != nil {
		return err
	}

	uu, err := url.Parse(str)
	*u = AcmeURL(*uu)
	return err
}

// VerifyCSR verifies that a Certificate Signature Request is well-formed.
//
// Note: this is the missing CertificateRequest.Verify() method
func VerifyCSR(csr *x509.CertificateRequest) error {
	// Compute the hash of the TBSCertificateRequest
	var hashID crypto.Hash
	var hash hash.Hash
	switch csr.SignatureAlgorithm {
	case x509.SHA1WithRSA:
		fallthrough
	case x509.ECDSAWithSHA1:
		hashID = crypto.SHA1
		hash = sha1.New()
	case x509.SHA256WithRSA:
		fallthrough
	case x509.ECDSAWithSHA256:
		hashID = crypto.SHA256
		hash = sha256.New()
	case x509.SHA384WithRSA:
		fallthrough
	case x509.ECDSAWithSHA384:
		hashID = crypto.SHA384
		hash = sha512.New384()
	case x509.SHA512WithRSA:
		fallthrough
	case x509.ECDSAWithSHA512:
		hashID = crypto.SHA512
		hash = sha512.New()
	default:
		return errors.New("Unsupported CSR signing algorithm")
	}
	_, _ = hash.Write(csr.RawTBSCertificateRequest) // Never returns an error
	inputHash := hash.Sum(nil)

	// Verify the signature using the public key in the CSR
	switch csr.SignatureAlgorithm {
	case x509.SHA1WithRSA:
		fallthrough
	case x509.SHA256WithRSA:
		fallthrough
	case x509.SHA384WithRSA:
		fallthrough
	case x509.SHA512WithRSA:
		rsaKey := csr.PublicKey.(*rsa.PublicKey)
		return rsa.VerifyPKCS1v15(rsaKey, hashID, inputHash, csr.Signature)
	case x509.ECDSAWithSHA1:
		fallthrough
	case x509.ECDSAWithSHA256:
		fallthrough
	case x509.ECDSAWithSHA384:
		fallthrough
	case x509.ECDSAWithSHA512:
		ecKey := csr.PublicKey.(*ecdsa.PublicKey)

		var sig struct{ R, S *big.Int }
		_, err := asn1.Unmarshal(csr.Signature, &sig)
		if err != nil {
			return err
		}

		if ecdsa.Verify(ecKey, inputHash, sig.R, sig.S) {
			return nil
		}

		return errors.New("Invalid ECDSA signature on CSR")
	}

	return errors.New("Unsupported CSR signing algorithm")
}

// SerialToString converts a certificate serial number (big.Int) to a String
// consistently.
func SerialToString(serial *big.Int) string {
	return fmt.Sprintf("%036x", serial)
}

// StringToSerial converts a string into a certificate serial number (big.Int)
// consistently.
func StringToSerial(serial string) (*big.Int, error) {
	var serialNum big.Int
	if !ValidSerial(serial) {
		return &serialNum, errors.New("Invalid serial number")
	}
	_, err := fmt.Sscanf(serial, "%036x", &serialNum)
	return &serialNum, err
}

func ValidSerial(serial string) bool {
	// Originally, serial numbers were 32 hex characters long. We later increased
	// them to 36, but we allow the shorter ones because they exist in some
	// production databases.
	if len(serial) < 32 && len(serial) > 36 {
		return false
	}
	_, err := hex.DecodeString(serial)
	if err != nil {
		return false
	}
	return true
}

// GetBuildID identifies what build is running.
func GetBuildID() (retID string) {
	retID = BuildID
	if retID == "" {
		retID = "Unspecified"
	}
	return
}

// GetBuildTime identifies when this build was made
func GetBuildTime() (retID string) {
	retID = BuildTime
	if retID == "" {
		retID = "Unspecified"
	}
	return
}

// GetBuildHost identifies the building host
func GetBuildHost() (retID string) {
	retID = BuildHost
	if retID == "" {
		retID = "Unspecified"
	}
	return
}

// UniqueNames returns the set of all unique names in the input.
func UniqueNames(names []string) (unique []string) {
	nameMap := make(map[string]int, len(names))
	for _, name := range names {
		nameMap[name] = 1
	}

	unique = make([]string, 0, len(nameMap))
	for name := range nameMap {
		unique = append(unique, name)
	}
	return
}

// LoadCertBundle loads a PEM bundle of certificates from disk
func LoadCertBundle(filename string) ([]*x509.Certificate, error) {
	bundleBytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	var bundle []*x509.Certificate
	var block *pem.Block
	rest := bundleBytes
	for {
		block, rest = pem.Decode(rest)
		if block == nil {
			break
		}
		if block.Type != "CERTIFICATE" {
			return nil, fmt.Errorf("Block has invalid type: %s", block.Type)
		}
		cert, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			return nil, err
		}
		bundle = append(bundle, cert)
	}

	if len(bundle) == 0 {
		return nil, fmt.Errorf("Bundle doesn't contain any certificates")
	}

	return bundle, nil
}

// LoadCert loads a PEM certificate specified by filename or returns a error
func LoadCert(filename string) (cert *x509.Certificate, err error) {
	certPEM, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	block, _ := pem.Decode(certPEM)
	if block == nil {
		return nil, fmt.Errorf("No data in cert PEM file %s", filename)
	}
	cert, err = x509.ParseCertificate(block.Bytes)
	return
}
<|endoftext|>


<commit_before>package chat

import (
	"fmt"
	"strings"
	"testing"

	"github.com/keybase/client/go/kbun"

	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/stretchr/testify/require"
)

func TestTranscript(t *testing.T) {
	runWithMemberTypes(t, func(mt chat1.ConversationMembersType) {
		// Only run this test for imp teams
		switch mt {
		case chat1.ConversationMembersType_IMPTEAMNATIVE,
			chat1.ConversationMembersType_IMPTEAMUPGRADE:
		default:
			return
		}

		ctc := makeChatTestContext(t, "TestTranscripts", 3)
		defer ctc.cleanup()
		users := ctc.users()

		tc1 := ctc.world.Tcs[users[0].Username]
		ctx := ctc.as(t, users[0]).startCtx

		displayName := strings.Join([]string{
			users[0].Username,
			users[1].Username,
			users[2].Username,
		}, ",")

		ncres, err := ctc.as(t, users[0]).chatLocalHandler().NewConversationLocal(ctx,
			chat1.NewConversationLocalArg{
				TlfName:          displayName,
				TopicType:        chat1.TopicType_CHAT,
				TlfVisibility:    keybase1.TLFVisibility_PRIVATE,
				MembersType:      mt,
				IdentifyBehavior: keybase1.TLFIdentifyBehavior_CHAT_CLI,
			})
		require.NoError(t, err)

		for i := range users {
			mustPostLocalForTest(t, ctc, users[i], ncres.Conv.Info,
				chat1.NewMessageBodyWithText(chat1.MessageText{
					Body: fmt.Sprintf("hello from user %d", i),
				}))
		}

		// Make a config for tests to ensure fetching multiple batches with
		// pagination.
		config := PullTranscriptConfig{
			messageCount: 10,
			batchSize:    2,
			batchCount:   5,
		}

		mctx := tc1.MetaContext().WithLogTag("REPORT")
		res, err := PullTranscript(mctx, tc1.Context().ConvSource,
			ncres.Conv.GetConvID().ConvIDStr(), nil, config)
		require.NoError(t, err)
		require.Len(t, res.Messages, 3)
		for i := range res.Messages {
			require.Equal(t, res.Messages[i].SenderUsername, users[2-i].Username)
		}

		mctx = tc1.MetaContext().WithLogTag("REPORT")
		usernames := []kbun.NormalizedUsername{
			kbun.NewNormalizedUsername(users[0].Username),
			kbun.NewNormalizedUsername(users[1].Username),
		}
		res, err = PullTranscript(mctx, tc1.Context().ConvSource,
			ncres.Conv.GetConvID().ConvIDStr(), usernames, config)
		require.NoError(t, err)
		require.Len(t, res.Messages, 2)
		// Messages from users[2] should be skipped.
		require.Equal(t, res.Messages[0].SenderUsername, users[1].Username)
		require.Equal(t, res.Messages[1].SenderUsername, users[0].Username)
	})
}

func TestTranscriptLimit(t *testing.T) {
	// Make sure the pagination is limited, so we don't end up digging for
	// messages in a busy channel for e.g. someone who hasn't even spoken
	// there.

	runWithMemberTypes(t, func(mt chat1.ConversationMembersType) {
		// Only run this test for imp teams
		switch mt {
		case chat1.ConversationMembersType_IMPTEAMNATIVE,
			chat1.ConversationMembersType_IMPTEAMUPGRADE:
		default:
			return
		}

		ctc := makeChatTestContext(t, "TestTranscripts", 2)
		defer ctc.cleanup()
		users := ctc.users()

		tc1 := ctc.world.Tcs[users[0].Username]
		ctx := ctc.as(t, users[0]).startCtx

		displayName := strings.Join([]string{
			users[0].Username,
			users[1].Username,
		}, ",")

		ncres, err := ctc.as(t, users[0]).chatLocalHandler().NewConversationLocal(ctx,
			chat1.NewConversationLocalArg{
				TlfName:          displayName,
				TopicType:        chat1.TopicType_CHAT,
				TlfVisibility:    keybase1.TLFVisibility_PRIVATE,
				MembersType:      mt,
				IdentifyBehavior: keybase1.TLFIdentifyBehavior_CHAT_CLI,
			})
		require.NoError(t, err)

		mustPostLocalForTest(t, ctc, users[1], ncres.Conv.Info,
			chat1.NewMessageBodyWithText(chat1.MessageText{
				Body: "hello chat",
			}))

		for i := 0; i < 10; i++ {
			mustPostLocalForTest(t, ctc, users[0], ncres.Conv.Info,
				chat1.NewMessageBodyWithText(chat1.MessageText{
					Body: fmt.Sprintf("hello message %d", i),
				}))
		}

		// With this config, we will not be able to dig through 10 messages
		// from users[0] to reach message from users[1].
		config := PullTranscriptConfig{
			messageCount: 5,
			batchSize:    2,
			batchCount:   3,
		}

		mctx := tc1.MetaContext().WithLogTag("REPORT")
		usernames := []kbun.NormalizedUsername{
			kbun.NewNormalizedUsername(users[1].Username),
		}
		res, err := PullTranscript(mctx, tc1.Context().ConvSource,
			ncres.Conv.GetConvID().ConvIDStr(), usernames, config)
		require.NoError(t, err)
		require.Len(t, res.Messages, 0)
	})
}
<commit_msg>skip transcripttest for now (#22523)<commit_after>package chat

import (
	"fmt"
	"strings"
	"testing"

	"github.com/keybase/client/go/kbun"

	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/stretchr/testify/require"
)

func TestTranscript(t *testing.T) {
	t.Skip("Y2K-1384")
	runWithMemberTypes(t, func(mt chat1.ConversationMembersType) {
		// Only run this test for imp teams
		switch mt {
		case chat1.ConversationMembersType_IMPTEAMNATIVE,
			chat1.ConversationMembersType_IMPTEAMUPGRADE:
		default:
			return
		}

		ctc := makeChatTestContext(t, "TestTranscripts", 3)
		defer ctc.cleanup()
		users := ctc.users()

		tc1 := ctc.world.Tcs[users[0].Username]
		ctx := ctc.as(t, users[0]).startCtx

		displayName := strings.Join([]string{
			users[0].Username,
			users[1].Username,
			users[2].Username,
		}, ",")

		ncres, err := ctc.as(t, users[0]).chatLocalHandler().NewConversationLocal(ctx,
			chat1.NewConversationLocalArg{
				TlfName:          displayName,
				TopicType:        chat1.TopicType_CHAT,
				TlfVisibility:    keybase1.TLFVisibility_PRIVATE,
				MembersType:      mt,
				IdentifyBehavior: keybase1.TLFIdentifyBehavior_CHAT_CLI,
			})
		require.NoError(t, err)

		for i := range users {
			mustPostLocalForTest(t, ctc, users[i], ncres.Conv.Info,
				chat1.NewMessageBodyWithText(chat1.MessageText{
					Body: fmt.Sprintf("hello from user %d", i),
				}))
		}

		// Make a config for tests to ensure fetching multiple batches with
		// pagination.
		config := PullTranscriptConfig{
			messageCount: 10,
			batchSize:    2,
			batchCount:   5,
		}

		mctx := tc1.MetaContext().WithLogTag("REPORT")
		res, err := PullTranscript(mctx, tc1.Context().ConvSource,
			ncres.Conv.GetConvID().ConvIDStr(), nil, config)
		require.NoError(t, err)
		require.Len(t, res.Messages, 3)
		for i := range res.Messages {
			require.Equal(t, res.Messages[i].SenderUsername, users[2-i].Username)
		}

		mctx = tc1.MetaContext().WithLogTag("REPORT")
		usernames := []kbun.NormalizedUsername{
			kbun.NewNormalizedUsername(users[0].Username),
			kbun.NewNormalizedUsername(users[1].Username),
		}
		res, err = PullTranscript(mctx, tc1.Context().ConvSource,
			ncres.Conv.GetConvID().ConvIDStr(), usernames, config)
		require.NoError(t, err)
		require.Len(t, res.Messages, 2)
		// Messages from users[2] should be skipped.
		require.Equal(t, res.Messages[0].SenderUsername, users[1].Username)
		require.Equal(t, res.Messages[1].SenderUsername, users[0].Username)
	})
}

func TestTranscriptLimit(t *testing.T) {
	t.Skip("Y2K-1384")
	// Make sure the pagination is limited, so we don't end up digging for
	// messages in a busy channel for e.g. someone who hasn't even spoken
	// there.

	runWithMemberTypes(t, func(mt chat1.ConversationMembersType) {
		// Only run this test for imp teams
		switch mt {
		case chat1.ConversationMembersType_IMPTEAMNATIVE,
			chat1.ConversationMembersType_IMPTEAMUPGRADE:
		default:
			return
		}

		ctc := makeChatTestContext(t, "TestTranscripts", 2)
		defer ctc.cleanup()
		users := ctc.users()

		tc1 := ctc.world.Tcs[users[0].Username]
		ctx := ctc.as(t, users[0]).startCtx

		displayName := strings.Join([]string{
			users[0].Username,
			users[1].Username,
		}, ",")

		ncres, err := ctc.as(t, users[0]).chatLocalHandler().NewConversationLocal(ctx,
			chat1.NewConversationLocalArg{
				TlfName:          displayName,
				TopicType:        chat1.TopicType_CHAT,
				TlfVisibility:    keybase1.TLFVisibility_PRIVATE,
				MembersType:      mt,
				IdentifyBehavior: keybase1.TLFIdentifyBehavior_CHAT_CLI,
			})
		require.NoError(t, err)

		mustPostLocalForTest(t, ctc, users[1], ncres.Conv.Info,
			chat1.NewMessageBodyWithText(chat1.MessageText{
				Body: "hello chat",
			}))

		for i := 0; i < 10; i++ {
			mustPostLocalForTest(t, ctc, users[0], ncres.Conv.Info,
				chat1.NewMessageBodyWithText(chat1.MessageText{
					Body: fmt.Sprintf("hello message %d", i),
				}))
		}

		// With this config, we will not be able to dig through 10 messages
		// from users[0] to reach message from users[1].
		config := PullTranscriptConfig{
			messageCount: 5,
			batchSize:    2,
			batchCount:   3,
		}

		mctx := tc1.MetaContext().WithLogTag("REPORT")
		usernames := []kbun.NormalizedUsername{
			kbun.NewNormalizedUsername(users[1].Username),
		}
		res, err := PullTranscript(mctx, tc1.Context().ConvSource,
			ncres.Conv.GetConvID().ConvIDStr(), usernames, config)
		require.NoError(t, err)
		require.Len(t, res.Messages, 0)
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"io"
	"os"
)

type Gopher struct {
    Name     string
    AgeYears int
}

type binWriter struct {
    w    io.Writer
    size int64
    err  error
}

// Write writes a value to the provided writer in little endian form.
func (w *binWriter) Write(v interface{}) {
    if w.err != nil {
        return
    }
    if w.err = binary.Write(w.w, binary.LittleEndian, v); w.err == nil {
        w.size += int64(binary.Size(v))
    }
}

func (g *Gopher) WriteTo(w io.Writer) (int64, error) {
    bw := &binWriter{w: w}
    bw.Write(int32(len(g.Name)))
    bw.Write([]byte(g.Name))
    bw.Write(int64(g.AgeYears))
    return bw.size, bw.err
}

func main() {
	g := Gopher{Name: "Hoge", AgeYears: 5}
	g.WriteTo(os.Stdout)
}
<commit_msg>特定のケースを処理するためにtype switchを使用します。<commit_after>package main

import (
	"encoding/binary"
	"io"
	"os"
)

type Gopher struct {
    Name     string
    AgeYears int
}

type binWriter struct {
    w    io.Writer
    size int64
    err  error
}

func (w *binWriter) Write(v interface{}) {
    if w.err != nil {
        return
    }
    switch v.(type) {
    case string:
        s := v.(string)
        w.Write(int32(len(s)))
        w.Write([]byte(s))
    case int:
        i := v.(int)
        w.Write(int64(i))
    default:
        if w.err = binary.Write(w.w, binary.LittleEndian, v); w.err == nil {
            w.size += int64(binary.Size(v))
        }
    }
}

func (g *Gopher) WriteTo(w io.Writer) (int64, error) {
    bw := &binWriter{w: w}
    bw.Write(g.Name)
    bw.Write(g.AgeYears)
    return bw.size, bw.err
}

func main() {
	g := Gopher{Name: "Hoge", AgeYears: 5}
	g.WriteTo(os.Stdout)
}
<|endoftext|>


<commit_before>// Package editorconfig can be used to parse and generate editorconfig files.
// For more information about editorconfig, see http://editorconfig.org/
package editorconfig

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"gopkg.in/ini.v1"
)

const (
	ConfigNameDefault = ".editorconfig"
)

// IndentStyle possible values
const (
	IndentStyleTab    = "tab"
	IndentStyleSpaces = "space"
)

// EndOfLine possible values
const (
	EndOfLineLf   = "lf"
	EndOfLineCr   = "cr"
	EndOfLineCrLf = "crlf"
)

// Charset possible values
const (
	CharsetLatin1  = "latin1"
	CharsetUTF8    = "utf-8"
	CharsetUTF16BE = "utf-16be"
	CharsetUTF16LE = "utf-16le"
)

// Definition represents a definition inside the .editorconfig file.
// E.g. a section of the file.
// The definition is composed of the selector ("*", "*.go", "*.{js.css}", etc),
// plus the properties of the selected files.
type Definition struct {
	Selector string `ini:"-" json:"-"`

	Charset                string `ini:"charset" json:"charset,omitempty"`
	IndentStyle            string `ini:"indent_style" json:"indent_style,omitempty"`
	IndentSize             string `ini:"indent_size" json:"indent_size,omitempty"`
	TabWidth               int    `ini:"tab_width" json:"tab_width,omitempty"`
	EndOfLine              string `ini:"end_of_line" json:"end_of_line,omitempty"`
	TrimTrailingWhitespace bool   `ini:"trim_trailing_whitespace" json:"trim_trailing_whitespace,omitempty"`
	InsertFinalNewline     bool   `ini:"insert_final_newline" json:"insert_final_newline,omitempty"`
}

// Editorconfig represents a .editorconfig file.
// It is composed by a "root" property, plus the definitions defined in the
// file.
type Editorconfig struct {
	Root        bool
	Definitions []*Definition
}

// ParseBytes parses from a slice of bytes.
func ParseBytes(data []byte) (*Editorconfig, error) {
	iniFile, err := ini.Load(data)
	if err != nil {
		return nil, err
	}

	editorConfig := &Editorconfig{}
	editorConfig.Root = iniFile.Section(ini.DEFAULT_SECTION).Key("root").MustBool(false)
	for _, sectionStr := range iniFile.SectionStrings() {
		if sectionStr == ini.DEFAULT_SECTION {
			continue
		}
		var (
			iniSection = iniFile.Section(sectionStr)
			definition = &Definition{}
		)
		err := iniSection.MapTo(&definition)
		if err != nil {
			return nil, err
		}

		// tab_width defaults to indent_size:
		// https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#tab_width
		if definition.TabWidth <= 0 {
			if num, err := strconv.Atoi(definition.IndentSize); err == nil {
				definition.TabWidth = num
			}
		}

		definition.Selector = sectionStr
		editorConfig.Definitions = append(editorConfig.Definitions, definition)
	}
	return editorConfig, nil
}

// ParseFile parses from a file.
func ParseFile(f string) (*Editorconfig, error) {
	data, err := ioutil.ReadFile(f)
	if err != nil {
		return nil, err
	}

	return ParseBytes(data)
}

var (
	regexpBraces = regexp.MustCompile("{.*}")
)

func filenameMatches(pattern, name string) bool {
	// basic match
	matched, _ := filepath.Match(pattern, name)
	if matched {
		return true
	}
	// foo/bar/main.go should match main.go
	matched, _ = filepath.Match(pattern, filepath.Base(name))
	if matched {
		return true
	}
	// foo should match foo/main.go
	matched, _ = filepath.Match(filepath.Join(pattern, "*"), name)
	if matched {
		return true
	}
	// *.{js,go} should match main.go
	if str := regexpBraces.FindString(pattern); len(str) > 0 {
		// remote initial "{" and final "}"
		str = strings.TrimPrefix(str, "{")
		str = strings.TrimSuffix(str, "}")

		// testing for empty brackets: "{}"
		if len(str) == 0 {
			patt := regexpBraces.ReplaceAllString(pattern, "*")
			matched, _ = filepath.Match(patt, filepath.Base(name))
			return matched
		}

		for _, patt := range strings.Split(str, ",") {
			patt = regexpBraces.ReplaceAllString(pattern, patt)
			matched, _ = filepath.Match(patt, filepath.Base(name))
			if matched {
				return true
			}
		}
	}
	return false
}

func (d *Definition) merge(md *Definition) {
	if len(d.Charset) == 0 {
		d.Charset = md.Charset
	}
	if len(d.IndentStyle) == 0 {
		d.IndentStyle = md.IndentStyle
	}
	if len(d.IndentSize) == 0 {
		d.IndentSize = md.IndentSize
	}
	if d.TabWidth <= 0 {
		d.TabWidth = md.TabWidth
	}
	if len(d.EndOfLine) == 0 {
		d.EndOfLine = md.EndOfLine
	}
	if !d.TrimTrailingWhitespace {
		d.TrimTrailingWhitespace = md.TrimTrailingWhitespace
	}
	if !d.InsertFinalNewline {
		d.InsertFinalNewline = md.InsertFinalNewline
	}
}

// GetDefinitionForFilename returns a definition for the given filename.
// The result is a merge of the selectors that matched the file.
// The last section has preference over the priors.
func (e *Editorconfig) GetDefinitionForFilename(name string) *Definition {
	def := &Definition{}
	for i := len(e.Definitions) - 1; i >= 0; i-- {
		actualDef := e.Definitions[i]
		if filenameMatches(actualDef.Selector, name) {
			def.merge(actualDef)
		}
	}
	return def
}

func boolToString(b bool) string {
	if b {
		return "true"
	}
	return "false"
}

// Serialize converts the Editorconfig to a slice of bytes, containing the
// content of the file in the INI format.
func (e *Editorconfig) Serialize() ([]byte, error) {
	var (
		iniFile = ini.Empty()
		buffer  = bytes.NewBuffer(nil)
	)
	iniFile.Section(ini.DEFAULT_SECTION).Comment = "http://editorconfig.org"
	if e.Root {
		iniFile.Section(ini.DEFAULT_SECTION).Key("root").SetValue(boolToString(e.Root))
	}
	for _, d := range e.Definitions {
		iniSec := iniFile.Section(d.Selector)
		if len(d.Charset) > 0 {
			iniSec.Key("charset").SetValue(d.Charset)
		}
		if len(d.IndentStyle) > 0 {
			iniSec.Key("indent_style").SetValue(d.IndentStyle)
		}
		if len(d.IndentSize) > 0 {
			iniSec.Key("indent_size").SetValue(d.IndentSize)
		}
		if d.TabWidth > 0 && strconv.Itoa(d.TabWidth) != d.IndentSize {
			iniSec.Key("tab_width").SetValue(strconv.Itoa(d.TabWidth))
		}
		if len(d.EndOfLine) > 0 {
			iniSec.Key("end_of_line").SetValue(d.EndOfLine)
		}
		if d.TrimTrailingWhitespace {
			iniSec.Key("trim_trailing_whitespace").SetValue(boolToString(d.TrimTrailingWhitespace))
		}
		if d.InsertFinalNewline {
			iniSec.Key("insert_final_newline").SetValue(boolToString(d.InsertFinalNewline))
		}
	}
	_, err := iniFile.WriteTo(buffer)
	if err != nil {
		return nil, err
	}
	return buffer.Bytes(), nil
}

// Save saves the Editorconfig to a compatible INI file.
func (e *Editorconfig) Save(filename string) error {
	data, err := e.Serialize()
	if err != nil {
		return err
	}
	return ioutil.WriteFile(filename, data, 0666)
}

// GetDefinitionForFilename given a filename, searches
// for .editorconfig files, starting from the file folder,
// walking through the previous folders, until it reaches a
// folder with `root = true`, and returns the right editorconfig
// definition for the given file.
func GetDefinitionForFilename(filename string) (*Definition, error) {
	return GetDefinitionForFilenameWithConfigname(filename, ConfigNameDefault)
}

func GetDefinitionForFilenameWithConfigname(filename string, configname string) (*Definition, error) {
	abs, err := filepath.Abs(filename)
	if err != nil {
		return nil, err
	}
	definition := &Definition{}

	dir := abs
	for dir != filepath.Dir(dir) {
		dir = filepath.Dir(dir)
		ecFile := filepath.Join(dir, configname)
		if _, err := os.Stat(ecFile); os.IsNotExist(err) {
			continue
		}
		ec, err := ParseFile(ecFile)
		if err != nil {
			return nil, err
		}
		definition.merge(ec.GetDefinitionForFilename(filename))
		if ec.Root {
			break
		}
	}
	return definition, nil
}
<commit_msg>Separate InsertToIniFile func<commit_after>// Package editorconfig can be used to parse and generate editorconfig files.
// For more information about editorconfig, see http://editorconfig.org/
package editorconfig

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"gopkg.in/ini.v1"
)

const (
	ConfigNameDefault = ".editorconfig"
)

// IndentStyle possible values
const (
	IndentStyleTab    = "tab"
	IndentStyleSpaces = "space"
)

// EndOfLine possible values
const (
	EndOfLineLf   = "lf"
	EndOfLineCr   = "cr"
	EndOfLineCrLf = "crlf"
)

// Charset possible values
const (
	CharsetLatin1  = "latin1"
	CharsetUTF8    = "utf-8"
	CharsetUTF16BE = "utf-16be"
	CharsetUTF16LE = "utf-16le"
)

// Definition represents a definition inside the .editorconfig file.
// E.g. a section of the file.
// The definition is composed of the selector ("*", "*.go", "*.{js.css}", etc),
// plus the properties of the selected files.
type Definition struct {
	Selector string `ini:"-" json:"-"`

	Charset                string `ini:"charset" json:"charset,omitempty"`
	IndentStyle            string `ini:"indent_style" json:"indent_style,omitempty"`
	IndentSize             string `ini:"indent_size" json:"indent_size,omitempty"`
	TabWidth               int    `ini:"tab_width" json:"tab_width,omitempty"`
	EndOfLine              string `ini:"end_of_line" json:"end_of_line,omitempty"`
	TrimTrailingWhitespace bool   `ini:"trim_trailing_whitespace" json:"trim_trailing_whitespace,omitempty"`
	InsertFinalNewline     bool   `ini:"insert_final_newline" json:"insert_final_newline,omitempty"`
}

// Editorconfig represents a .editorconfig file.
// It is composed by a "root" property, plus the definitions defined in the
// file.
type Editorconfig struct {
	Root        bool
	Definitions []*Definition
}

// ParseBytes parses from a slice of bytes.
func ParseBytes(data []byte) (*Editorconfig, error) {
	iniFile, err := ini.Load(data)
	if err != nil {
		return nil, err
	}

	editorConfig := &Editorconfig{}
	editorConfig.Root = iniFile.Section(ini.DEFAULT_SECTION).Key("root").MustBool(false)
	for _, sectionStr := range iniFile.SectionStrings() {
		if sectionStr == ini.DEFAULT_SECTION {
			continue
		}
		var (
			iniSection = iniFile.Section(sectionStr)
			definition = &Definition{}
		)
		err := iniSection.MapTo(&definition)
		if err != nil {
			return nil, err
		}

		// tab_width defaults to indent_size:
		// https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#tab_width
		if definition.TabWidth <= 0 {
			if num, err := strconv.Atoi(definition.IndentSize); err == nil {
				definition.TabWidth = num
			}
		}

		definition.Selector = sectionStr
		editorConfig.Definitions = append(editorConfig.Definitions, definition)
	}
	return editorConfig, nil
}

// ParseFile parses from a file.
func ParseFile(f string) (*Editorconfig, error) {
	data, err := ioutil.ReadFile(f)
	if err != nil {
		return nil, err
	}

	return ParseBytes(data)
}

var (
	regexpBraces = regexp.MustCompile("{.*}")
)

func filenameMatches(pattern, name string) bool {
	// basic match
	matched, _ := filepath.Match(pattern, name)
	if matched {
		return true
	}
	// foo/bar/main.go should match main.go
	matched, _ = filepath.Match(pattern, filepath.Base(name))
	if matched {
		return true
	}
	// foo should match foo/main.go
	matched, _ = filepath.Match(filepath.Join(pattern, "*"), name)
	if matched {
		return true
	}
	// *.{js,go} should match main.go
	if str := regexpBraces.FindString(pattern); len(str) > 0 {
		// remote initial "{" and final "}"
		str = strings.TrimPrefix(str, "{")
		str = strings.TrimSuffix(str, "}")

		// testing for empty brackets: "{}"
		if len(str) == 0 {
			patt := regexpBraces.ReplaceAllString(pattern, "*")
			matched, _ = filepath.Match(patt, filepath.Base(name))
			return matched
		}

		for _, patt := range strings.Split(str, ",") {
			patt = regexpBraces.ReplaceAllString(pattern, patt)
			matched, _ = filepath.Match(patt, filepath.Base(name))
			if matched {
				return true
			}
		}
	}
	return false
}

func (d *Definition) merge(md *Definition) {
	if len(d.Charset) == 0 {
		d.Charset = md.Charset
	}
	if len(d.IndentStyle) == 0 {
		d.IndentStyle = md.IndentStyle
	}
	if len(d.IndentSize) == 0 {
		d.IndentSize = md.IndentSize
	}
	if d.TabWidth <= 0 {
		d.TabWidth = md.TabWidth
	}
	if len(d.EndOfLine) == 0 {
		d.EndOfLine = md.EndOfLine
	}
	if !d.TrimTrailingWhitespace {
		d.TrimTrailingWhitespace = md.TrimTrailingWhitespace
	}
	if !d.InsertFinalNewline {
		d.InsertFinalNewline = md.InsertFinalNewline
	}
}

func (d *Definition) InsertToIniFile(iniFile *ini.File) {
		iniSec := iniFile.Section(d.Selector)
		if len(d.Charset) > 0 {
			iniSec.Key("charset").SetValue(d.Charset)
		}
		if len(d.IndentStyle) > 0 {
			iniSec.Key("indent_style").SetValue(d.IndentStyle)
		}
		if len(d.IndentSize) > 0 {
			iniSec.Key("indent_size").SetValue(d.IndentSize)
		}
		if d.TabWidth > 0 && strconv.Itoa(d.TabWidth) != d.IndentSize {
			iniSec.Key("tab_width").SetValue(strconv.Itoa(d.TabWidth))
		}
		if len(d.EndOfLine) > 0 {
			iniSec.Key("end_of_line").SetValue(d.EndOfLine)
		}
		if d.TrimTrailingWhitespace {
			iniSec.Key("trim_trailing_whitespace").SetValue(boolToString(d.TrimTrailingWhitespace))
		}
		if d.InsertFinalNewline {
			iniSec.Key("insert_final_newline").SetValue(boolToString(d.InsertFinalNewline))
		}
}

// GetDefinitionForFilename returns a definition for the given filename.
// The result is a merge of the selectors that matched the file.
// The last section has preference over the priors.
func (e *Editorconfig) GetDefinitionForFilename(name string) *Definition {
	def := &Definition{}
	for i := len(e.Definitions) - 1; i >= 0; i-- {
		actualDef := e.Definitions[i]
		if filenameMatches(actualDef.Selector, name) {
			def.merge(actualDef)
		}
	}
	return def
}

func boolToString(b bool) string {
	if b {
		return "true"
	}
	return "false"
}

// Serialize converts the Editorconfig to a slice of bytes, containing the
// content of the file in the INI format.
func (e *Editorconfig) Serialize() ([]byte, error) {
	var (
		iniFile = ini.Empty()
		buffer  = bytes.NewBuffer(nil)
	)
	iniFile.Section(ini.DEFAULT_SECTION).Comment = "http://editorconfig.org"
	if e.Root {
		iniFile.Section(ini.DEFAULT_SECTION).Key("root").SetValue(boolToString(e.Root))
	}
	for _, d := range e.Definitions {
		d.InsertToIniFile(iniFile)
	}
	_, err := iniFile.WriteTo(buffer)
	if err != nil {
		return nil, err
	}
	return buffer.Bytes(), nil
}

// Save saves the Editorconfig to a compatible INI file.
func (e *Editorconfig) Save(filename string) error {
	data, err := e.Serialize()
	if err != nil {
		return err
	}
	return ioutil.WriteFile(filename, data, 0666)
}

// GetDefinitionForFilename given a filename, searches
// for .editorconfig files, starting from the file folder,
// walking through the previous folders, until it reaches a
// folder with `root = true`, and returns the right editorconfig
// definition for the given file.
func GetDefinitionForFilename(filename string) (*Definition, error) {
	return GetDefinitionForFilenameWithConfigname(filename, ConfigNameDefault)
}

func GetDefinitionForFilenameWithConfigname(filename string, configname string) (*Definition, error) {
	abs, err := filepath.Abs(filename)
	if err != nil {
		return nil, err
	}
	definition := &Definition{}

	dir := abs
	for dir != filepath.Dir(dir) {
		dir = filepath.Dir(dir)
		ecFile := filepath.Join(dir, configname)
		if _, err := os.Stat(ecFile); os.IsNotExist(err) {
			continue
		}
		ec, err := ParseFile(ecFile)
		if err != nil {
			return nil, err
		}
		definition.merge(ec.GetDefinitionForFilename(filename))
		if ec.Root {
			break
		}
	}
	return definition, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"os/signal"
	"syscall"
)

func handleClient(conn net.Conn) error {
	r := bufio.NewReader(conn)
	_, err := r.ReadByte()
	if err != nil {
		return err
	}
	w := bufio.NewWriter(conn)
	_, err = w.WriteString("HTTP/1.0 200 OK\n")
	if err != nil {
		return err
	}
	w.Flush()

	return nil
}

func Run(host string, port int) int {
	fmt.Printf("--> binding to %s:%d\n", host, port)

	addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port))
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		return -1
	}

	ln, err := net.ListenTCP("tcp", addr)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		return -1
	}

	sigs := make(chan os.Signal, 1)

	signal.Notify(sigs, syscall.SIGCHLD)
	go func() {
		<-sigs
		var status syscall.WaitStatus
		var rusage syscall.Rusage
		_, err := syscall.Wait4(-1, &status, 0, &rusage)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			return
		}
	}()

	for {
		conn, err := ln.Accept()
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			continue
		}
		fmt.Printf(".")

		ret, _, errno := syscall.Syscall(syscall.SYS_FORK, 0, 0, 0)
		if errno != 0 {
			return int(errno)
		}
		if ret != 0 {
			conn.Close() // parent process close
			continue
		}

		if err := handleClient(conn); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			continue
		}

		conn.Close() // child process close
		os.Exit(0) // child process exit
	}

	return 0
}
<commit_msg>Kill zombie process<commit_after>package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"os/signal"
	"syscall"
)

func handleClient(conn net.Conn) error {
	r := bufio.NewReader(conn)
	_, err := r.ReadByte()
	if err != nil {
		return err
	}
	w := bufio.NewWriter(conn)
	_, err = w.WriteString("HTTP/1.0 200 OK\n")
	if err != nil {
		return err
	}
	w.Flush()

	return nil
}

func Run(host string, port int) int {
	fmt.Printf("--> binding to %s:%d\n", host, port)

	addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port))
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		return -1
	}

	ln, err := net.ListenTCP("tcp", addr)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		return -1
	}

	sigs := make(chan os.Signal, 1)

	signal.Notify(sigs, syscall.SIGCHLD)
	go func() {
		var status syscall.WaitStatus
		var rusage syscall.Rusage
		for {
			<-sigs
			_, err := syscall.Wait4(-1, &status, 0, &rusage)
			if err != nil {
				fmt.Fprintf(os.Stderr, "%s\n", err)
			}
		}
	}()

	for {
		conn, err := ln.Accept()
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			continue
		}
		fmt.Printf(".")

		ret, _, errno := syscall.Syscall(syscall.SYS_FORK, 0, 0, 0)
		if errno != 0 {
			return int(errno)
		}
		if ret != 0 {
			conn.Close() // parent process close
			continue
		}

		if err := handleClient(conn); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			continue
		}

		conn.Close() // child process close
		os.Exit(0) // child process exit
	}

	return 0
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"runtime"

	"github.com/containers/buildah"
	"github.com/containers/buildah/define"
	"github.com/containers/buildah/internal/util"
	buildahcli "github.com/containers/buildah/pkg/cli"
	"github.com/containers/buildah/pkg/parse"
	"github.com/containers/common/pkg/auth"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

type pullOptions struct {
	allTags          bool
	authfile         string
	blobCache        string
	certDir          string
	creds            string
	signaturePolicy  string
	quiet            bool
	removeSignatures bool
	tlsVerify        bool
	decryptionKeys   []string
	pullPolicy       string
}

func init() {
	var (
		opts pullOptions

		pullDescription = `  Pulls an image from a registry and stores it locally.
  An image can be pulled using its tag or digest. If a tag is not
  specified, the image with the 'latest' tag (if it exists) is pulled.`
	)

	pullCommand := &cobra.Command{
		Use:   "pull",
		Short: "Pull an image from the specified location",
		Long:  pullDescription,
		RunE: func(cmd *cobra.Command, args []string) error {
			return pullCmd(cmd, args, opts)
		},
		Example: `buildah pull imagename
  buildah pull docker-daemon:imagename:imagetag
  buildah pull myregistry/myrepository/imagename:imagetag`,
	}
	pullCommand.SetUsageTemplate(UsageTemplate())

	flags := pullCommand.Flags()
	flags.SetInterspersed(false)
	flags.BoolVarP(&opts.allTags, "all-tags", "a", false, "download all tagged images in the repository")
	flags.StringVar(&opts.authfile, "authfile", auth.GetDefaultAuthFile(), "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
	flags.StringVar(&opts.blobCache, "blob-cache", "", "store copies of pulled image blobs in the specified directory")
	flags.StringVar(&opts.certDir, "cert-dir", "", "use certificates at the specified path to access the registry")
	flags.StringVar(&opts.creds, "creds", "", "use `[username[:password]]` for accessing the registry")
	flags.StringVar(&opts.pullPolicy, "policy", "missing", "missing, always, or never.")
	flags.BoolVarP(&opts.removeSignatures, "remove-signatures", "", false, "don't copy signatures when pulling image")
	flags.StringVar(&opts.signaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
	flags.StringSliceVar(&opts.decryptionKeys, "decryption-key", nil, "key needed to decrypt the image")
	if err := flags.MarkHidden("signature-policy"); err != nil {
		panic(fmt.Sprintf("error marking signature-policy as hidden: %v", err))
	}
	flags.BoolVarP(&opts.quiet, "quiet", "q", false, "don't output progress information when pulling images")
	flags.String("os", runtime.GOOS, "prefer `OS` instead of the running OS for choosing images")
	flags.String("arch", runtime.GOARCH, "prefer `ARCH` instead of the architecture of the machine for choosing images")
	flags.StringSlice("platform", []string{parse.DefaultPlatform()}, "prefer OS/ARCH instead of the current operating system and architecture for choosing images")
	flags.String("variant", "", "override the `variant` of the specified image")
	flags.BoolVar(&opts.tlsVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry. TLS verification cannot be used when talking to an insecure registry.")
	if err := flags.MarkHidden("blob-cache"); err != nil {
		panic(fmt.Sprintf("error marking blob-cache as hidden: %v", err))
	}

	rootCmd.AddCommand(pullCommand)
}

func pullCmd(c *cobra.Command, args []string, iopts pullOptions) error {
	if len(args) == 0 {
		return errors.New("an image name must be specified")
	}
	if err := buildahcli.VerifyFlagsArgsOrder(args); err != nil {
		return err
	}
	if len(args) > 1 {
		return errors.New("too many arguments specified")
	}
	if err := auth.CheckAuthFile(iopts.authfile); err != nil {
		return err
	}

	systemContext, err := parse.SystemContextFromOptions(c)
	if err != nil {
		return fmt.Errorf("error building system context: %w", err)
	}
	platforms, err := parse.PlatformsFromOptions(c)
	if err != nil {
		return err
	}
	if len(platforms) > 1 {
		logrus.Warnf("ignoring platforms other than %+v: %+v", platforms[0], platforms[1:])
	}

	store, err := getStore(c)
	if err != nil {
		return err
	}

	decConfig, err := util.DecryptConfig(iopts.decryptionKeys)
	if err != nil {
		return fmt.Errorf("unable to obtain decrypt config: %w", err)
	}

	policy, ok := define.PolicyMap[iopts.pullPolicy]
	if !ok {
		return fmt.Errorf("unsupported pull policy %q", iopts.pullPolicy)
	}
	options := buildah.PullOptions{
		SignaturePolicyPath: iopts.signaturePolicy,
		Store:               store,
		SystemContext:       systemContext,
		BlobDirectory:       iopts.blobCache,
		AllTags:             iopts.allTags,
		ReportWriter:        os.Stderr,
		RemoveSignatures:    iopts.removeSignatures,
		MaxRetries:          buildahcli.MaxPullPushRetries,
		RetryDelay:          buildahcli.PullPushRetryDelay,
		OciDecryptConfig:    decConfig,
		PullPolicy:          policy,
	}

	if iopts.quiet {
		options.ReportWriter = nil // Turns off logging output
	}

	id, err := buildah.Pull(getContext(), args[0], options)
	if err != nil {
		return err
	}
	fmt.Printf("%s\n", id)
	return nil
}
<commit_msg>cmd/buildah.pullCmd: complain about DecryptConfig/EncryptConfig<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"runtime"

	"github.com/containers/buildah"
	"github.com/containers/buildah/define"
	"github.com/containers/buildah/internal/util"
	buildahcli "github.com/containers/buildah/pkg/cli"
	"github.com/containers/buildah/pkg/parse"
	"github.com/containers/common/pkg/auth"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

type pullOptions struct {
	allTags          bool
	authfile         string
	blobCache        string
	certDir          string
	creds            string
	signaturePolicy  string
	quiet            bool
	removeSignatures bool
	tlsVerify        bool
	decryptionKeys   []string
	pullPolicy       string
}

func init() {
	var (
		opts pullOptions

		pullDescription = `  Pulls an image from a registry and stores it locally.
  An image can be pulled using its tag or digest. If a tag is not
  specified, the image with the 'latest' tag (if it exists) is pulled.`
	)

	pullCommand := &cobra.Command{
		Use:   "pull",
		Short: "Pull an image from the specified location",
		Long:  pullDescription,
		RunE: func(cmd *cobra.Command, args []string) error {
			return pullCmd(cmd, args, opts)
		},
		Example: `buildah pull imagename
  buildah pull docker-daemon:imagename:imagetag
  buildah pull myregistry/myrepository/imagename:imagetag`,
	}
	pullCommand.SetUsageTemplate(UsageTemplate())

	flags := pullCommand.Flags()
	flags.SetInterspersed(false)
	flags.BoolVarP(&opts.allTags, "all-tags", "a", false, "download all tagged images in the repository")
	flags.StringVar(&opts.authfile, "authfile", auth.GetDefaultAuthFile(), "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
	flags.StringVar(&opts.blobCache, "blob-cache", "", "store copies of pulled image blobs in the specified directory")
	flags.StringVar(&opts.certDir, "cert-dir", "", "use certificates at the specified path to access the registry")
	flags.StringVar(&opts.creds, "creds", "", "use `[username[:password]]` for accessing the registry")
	flags.StringVar(&opts.pullPolicy, "policy", "missing", "missing, always, or never.")
	flags.BoolVarP(&opts.removeSignatures, "remove-signatures", "", false, "don't copy signatures when pulling image")
	flags.StringVar(&opts.signaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
	flags.StringSliceVar(&opts.decryptionKeys, "decryption-key", nil, "key needed to decrypt the image")
	if err := flags.MarkHidden("signature-policy"); err != nil {
		panic(fmt.Sprintf("error marking signature-policy as hidden: %v", err))
	}
	flags.BoolVarP(&opts.quiet, "quiet", "q", false, "don't output progress information when pulling images")
	flags.String("os", runtime.GOOS, "prefer `OS` instead of the running OS for choosing images")
	flags.String("arch", runtime.GOARCH, "prefer `ARCH` instead of the architecture of the machine for choosing images")
	flags.StringSlice("platform", []string{parse.DefaultPlatform()}, "prefer OS/ARCH instead of the current operating system and architecture for choosing images")
	flags.String("variant", "", "override the `variant` of the specified image")
	flags.BoolVar(&opts.tlsVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry. TLS verification cannot be used when talking to an insecure registry.")
	if err := flags.MarkHidden("blob-cache"); err != nil {
		panic(fmt.Sprintf("error marking blob-cache as hidden: %v", err))
	}

	rootCmd.AddCommand(pullCommand)
}

func pullCmd(c *cobra.Command, args []string, iopts pullOptions) error {
	if len(args) == 0 {
		return errors.New("an image name must be specified")
	}
	if err := buildahcli.VerifyFlagsArgsOrder(args); err != nil {
		return err
	}
	if len(args) > 1 {
		return errors.New("too many arguments specified")
	}
	if err := auth.CheckAuthFile(iopts.authfile); err != nil {
		return err
	}

	systemContext, err := parse.SystemContextFromOptions(c)
	if err != nil {
		return fmt.Errorf("error building system context: %w", err)
	}
	platforms, err := parse.PlatformsFromOptions(c)
	if err != nil {
		return err
	}
	if len(platforms) > 1 {
		logrus.Warnf("ignoring platforms other than %+v: %+v", platforms[0], platforms[1:])
	}

	store, err := getStore(c)
	if err != nil {
		return err
	}

	decConfig, err := util.DecryptConfig(iopts.decryptionKeys)
	if err != nil {
		return fmt.Errorf("unable to obtain decryption config: %w", err)
	}

	policy, ok := define.PolicyMap[iopts.pullPolicy]
	if !ok {
		return fmt.Errorf("unsupported pull policy %q", iopts.pullPolicy)
	}
	options := buildah.PullOptions{
		SignaturePolicyPath: iopts.signaturePolicy,
		Store:               store,
		SystemContext:       systemContext,
		BlobDirectory:       iopts.blobCache,
		AllTags:             iopts.allTags,
		ReportWriter:        os.Stderr,
		RemoveSignatures:    iopts.removeSignatures,
		MaxRetries:          buildahcli.MaxPullPushRetries,
		RetryDelay:          buildahcli.PullPushRetryDelay,
		OciDecryptConfig:    decConfig,
		PullPolicy:          policy,
	}

	if iopts.quiet {
		options.ReportWriter = nil // Turns off logging output
	}

	id, err := buildah.Pull(getContext(), args[0], options)
	if err != nil {
		return err
	}
	fmt.Printf("%s\n", id)
	return nil
}
<|endoftext|>