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

package tls

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/des"
	"crypto/hmac"
	"crypto/rc4"
	"crypto/sha1"
	"crypto/x509"
	"hash"
)

// a keyAgreement implements the client and server side of a TLS key agreement
// protocol by generating and processing key exchange messages.
type keyAgreement interface {
	// On the server side, the first two methods are called in order.

	// In the case that the key agreement protocol doesn't use a
	// ServerKeyExchange message, generateServerKeyExchange can return nil,
	// nil.
	generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
	processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)

	// On the client side, the next two methods are called in order.

	// This method may not be called if the server doesn't send a
	// ServerKeyExchange message.
	processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
	generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
}

// A cipherSuite is a specific combination of key agreement, cipher and MAC
// function. All cipher suites currently assume RSA key agreement.
type cipherSuite struct {
	id uint16
	// the lengths, in bytes, of the key material needed for each component.
	keyLen int
	macLen int
	ivLen  int
	ka     func() keyAgreement
	// If elliptic is set, a server will only consider this ciphersuite if
	// the ClientHello indicated that the client supports an elliptic curve
	// and point format that we can handle.
	elliptic bool
	cipher   func(key, iv []byte, isRead bool) interface{}
	mac      func(version uint16, macKey []byte) macFunction
}

var cipherSuites = []*cipherSuite{
	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, false, cipherRC4, macSHA1},
	{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, false, cipher3DES, macSHA1},
	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, false, cipherAES, macSHA1},
	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, true, cipherRC4, macSHA1},
	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, true, cipher3DES, macSHA1},
	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, true, cipherAES, macSHA1},
}

func cipherRC4(key, iv []byte, isRead bool) interface{} {
	cipher, _ := rc4.NewCipher(key)
	return cipher
}

func cipher3DES(key, iv []byte, isRead bool) interface{} {
	block, _ := des.NewTripleDESCipher(key)
	if isRead {
		return cipher.NewCBCDecrypter(block, iv)
	}
	return cipher.NewCBCEncrypter(block, iv)
}

func cipherAES(key, iv []byte, isRead bool) interface{} {
	block, _ := aes.NewCipher(key)
	if isRead {
		return cipher.NewCBCDecrypter(block, iv)
	}
	return cipher.NewCBCEncrypter(block, iv)
}

// macSHA1 returns a macFunction for the given protocol version.
func macSHA1(version uint16, key []byte) macFunction {
	if version == versionSSL30 {
		mac := ssl30MAC{
			h:   sha1.New(),
			key: make([]byte, len(key)),
		}
		copy(mac.key, key)
		return mac
	}
	return tls10MAC{hmac.New(sha1.New, key)}
}

type macFunction interface {
	Size() int
	MAC(digestBuf, seq, data []byte) []byte
}

// ssl30MAC implements the SSLv3 MAC function, as defined in
// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 5.2.3.1
type ssl30MAC struct {
	h   hash.Hash
	key []byte
}

func (s ssl30MAC) Size() int {
	return s.h.Size()
}

var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}

var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}

func (s ssl30MAC) MAC(digestBuf, seq, record []byte) []byte {
	padLength := 48
	if s.h.Size() == 20 {
		padLength = 40
	}

	s.h.Reset()
	s.h.Write(s.key)
	s.h.Write(ssl30Pad1[:padLength])
	s.h.Write(seq)
	s.h.Write(record[:1])
	s.h.Write(record[3:5])
	s.h.Write(record[recordHeaderLen:])
	digestBuf = s.h.Sum(digestBuf[:0])

	s.h.Reset()
	s.h.Write(s.key)
	s.h.Write(ssl30Pad2[:padLength])
	s.h.Write(digestBuf)
	return s.h.Sum(digestBuf[:0])
}

// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3.
type tls10MAC struct {
	h hash.Hash
}

func (s tls10MAC) Size() int {
	return s.h.Size()
}

func (s tls10MAC) MAC(digestBuf, seq, record []byte) []byte {
	s.h.Reset()
	s.h.Write(seq)
	s.h.Write(record)
	return s.h.Sum(digestBuf[:0])
}

func rsaKA() keyAgreement {
	return rsaKeyAgreement{}
}

func ecdheRSAKA() keyAgreement {
	return new(ecdheRSAKeyAgreement)
}

// mutualCipherSuite returns a cipherSuite given a list of supported
// ciphersuites and the id requested by the peer.
func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
	for _, id := range have {
		if id == want {
			for _, suite := range cipherSuites {
				if suite.id == want {
					return suite
				}
			}
			return nil
		}
	}
	return nil
}

// A list of the possible cipher suite ids. Taken from
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
const (
	TLS_RSA_WITH_RC4_128_SHA            uint16 = 0x0005
	TLS_RSA_WITH_3DES_EDE_CBC_SHA       uint16 = 0x000a
	TLS_RSA_WITH_AES_128_CBC_SHA        uint16 = 0x002f
	TLS_ECDHE_RSA_WITH_RC4_128_SHA      uint16 = 0xc011
	TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA  uint16 = 0xc013
)
<commit_msg>tls: add AES256 ciphers<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tls

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/des"
	"crypto/hmac"
	"crypto/rc4"
	"crypto/sha1"
	"crypto/x509"
	"hash"
)

// a keyAgreement implements the client and server side of a TLS key agreement
// protocol by generating and processing key exchange messages.
type keyAgreement interface {
	// On the server side, the first two methods are called in order.

	// In the case that the key agreement protocol doesn't use a
	// ServerKeyExchange message, generateServerKeyExchange can return nil,
	// nil.
	generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
	processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)

	// On the client side, the next two methods are called in order.

	// This method may not be called if the server doesn't send a
	// ServerKeyExchange message.
	processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
	generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
}

// A cipherSuite is a specific combination of key agreement, cipher and MAC
// function. All cipher suites currently assume RSA key agreement.
type cipherSuite struct {
	id uint16
	// the lengths, in bytes, of the key material needed for each component.
	keyLen int
	macLen int
	ivLen  int
	ka     func() keyAgreement
	// If elliptic is set, a server will only consider this ciphersuite if
	// the ClientHello indicated that the client supports an elliptic curve
	// and point format that we can handle.
	elliptic bool
	cipher   func(key, iv []byte, isRead bool) interface{}
	mac      func(version uint16, macKey []byte) macFunction
}

var cipherSuites = []*cipherSuite{
	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, false, cipherRC4, macSHA1},
	{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, false, cipher3DES, macSHA1},
	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, false, cipherAES, macSHA1},
	{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, false, cipherAES, macSHA1},
	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, true, cipherRC4, macSHA1},
	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, true, cipher3DES, macSHA1},
	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, true, cipherAES, macSHA1},
	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, true, cipherAES, macSHA1},
}

func cipherRC4(key, iv []byte, isRead bool) interface{} {
	cipher, _ := rc4.NewCipher(key)
	return cipher
}

func cipher3DES(key, iv []byte, isRead bool) interface{} {
	block, _ := des.NewTripleDESCipher(key)
	if isRead {
		return cipher.NewCBCDecrypter(block, iv)
	}
	return cipher.NewCBCEncrypter(block, iv)
}

func cipherAES(key, iv []byte, isRead bool) interface{} {
	block, _ := aes.NewCipher(key)
	if isRead {
		return cipher.NewCBCDecrypter(block, iv)
	}
	return cipher.NewCBCEncrypter(block, iv)
}

// macSHA1 returns a macFunction for the given protocol version.
func macSHA1(version uint16, key []byte) macFunction {
	if version == versionSSL30 {
		mac := ssl30MAC{
			h:   sha1.New(),
			key: make([]byte, len(key)),
		}
		copy(mac.key, key)
		return mac
	}
	return tls10MAC{hmac.New(sha1.New, key)}
}

type macFunction interface {
	Size() int
	MAC(digestBuf, seq, data []byte) []byte
}

// ssl30MAC implements the SSLv3 MAC function, as defined in
// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 5.2.3.1
type ssl30MAC struct {
	h   hash.Hash
	key []byte
}

func (s ssl30MAC) Size() int {
	return s.h.Size()
}

var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}

var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}

func (s ssl30MAC) MAC(digestBuf, seq, record []byte) []byte {
	padLength := 48
	if s.h.Size() == 20 {
		padLength = 40
	}

	s.h.Reset()
	s.h.Write(s.key)
	s.h.Write(ssl30Pad1[:padLength])
	s.h.Write(seq)
	s.h.Write(record[:1])
	s.h.Write(record[3:5])
	s.h.Write(record[recordHeaderLen:])
	digestBuf = s.h.Sum(digestBuf[:0])

	s.h.Reset()
	s.h.Write(s.key)
	s.h.Write(ssl30Pad2[:padLength])
	s.h.Write(digestBuf)
	return s.h.Sum(digestBuf[:0])
}

// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3.
type tls10MAC struct {
	h hash.Hash
}

func (s tls10MAC) Size() int {
	return s.h.Size()
}

func (s tls10MAC) MAC(digestBuf, seq, record []byte) []byte {
	s.h.Reset()
	s.h.Write(seq)
	s.h.Write(record)
	return s.h.Sum(digestBuf[:0])
}

func rsaKA() keyAgreement {
	return rsaKeyAgreement{}
}

func ecdheRSAKA() keyAgreement {
	return new(ecdheRSAKeyAgreement)
}

// mutualCipherSuite returns a cipherSuite given a list of supported
// ciphersuites and the id requested by the peer.
func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
	for _, id := range have {
		if id == want {
			for _, suite := range cipherSuites {
				if suite.id == want {
					return suite
				}
			}
			return nil
		}
	}
	return nil
}

// A list of the possible cipher suite ids. Taken from
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
const (
	TLS_RSA_WITH_RC4_128_SHA            uint16 = 0x0005
	TLS_RSA_WITH_3DES_EDE_CBC_SHA       uint16 = 0x000a
	TLS_RSA_WITH_AES_128_CBC_SHA        uint16 = 0x002f
	TLS_RSA_WITH_AES_256_CBC_SHA        uint16 = 0x0035
	TLS_ECDHE_RSA_WITH_RC4_128_SHA      uint16 = 0xc011
	TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA  uint16 = 0xc013
	TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA  uint16 = 0xc014
)
<|endoftext|>


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

package x509

import (
	"errors"
	"syscall"
	"unsafe"
)

// Creates a new *syscall.CertContext representing the leaf certificate in an in-memory
// certificate store containing itself and all of the intermediate certificates specified
// in the opts.Intermediates CertPool.
//
// A pointer to the in-memory store is available in the returned CertContext's Store field.
// The store is automatically freed when the CertContext is freed using
// syscall.CertFreeCertificateContext.
func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertContext, error) {
	var storeCtx *syscall.CertContext

	leafCtx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &leaf.Raw[0], uint32(len(leaf.Raw)))
	if err != nil {
		return nil, err
	}
	defer syscall.CertFreeCertificateContext(leafCtx)

	handle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0)
	if err != nil {
		return nil, err
	}
	defer syscall.CertCloseStore(handle, 0)

	err = syscall.CertAddCertificateContextToStore(handle, leafCtx, syscall.CERT_STORE_ADD_ALWAYS, &storeCtx)
	if err != nil {
		return nil, err
	}

	if opts.Intermediates != nil {
		for _, intermediate := range opts.Intermediates.certs {
			ctx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &intermediate.Raw[0], uint32(len(intermediate.Raw)))
			if err != nil {
				return nil, err
			}

			err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
			if err != nil {
				return nil, err
			}

			err = syscall.CertFreeCertificateContext(ctx)
			if err != nil {
				return nil, err
			}
		}
	}

	return storeCtx, nil
}

// extractSimpleChain extracts the final certificate chain from a CertSimpleChain.
func extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*Certificate, err error) {
	if simpleChain == nil || count == 0 {
		return nil, errors.New("x509: invalid simple chain")
	}

	simpleChains := (*[1 << 20]*syscall.CertSimpleChain)(unsafe.Pointer(simpleChain))[:]
	lastChain := simpleChains[count-1]
	elements := (*[1 << 20]*syscall.CertChainElement)(unsafe.Pointer(lastChain.Elements))[:]
	for i := 0; i < int(lastChain.NumElements); i++ {
		// Copy the buf, since ParseCertificate does not create its own copy.
		cert := elements[i].CertContext
		encodedCert := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
		buf := make([]byte, cert.Length)
		copy(buf, encodedCert[:])
		parsedCert, err := ParseCertificate(buf)
		if err != nil {
			return nil, err
		}
		chain = append(chain, parsedCert)
	}

	return chain, nil
}

// checkChainTrustStatus checks the trust status of the certificate chain, translating
// any errors it finds into Go errors in the process.
func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error {
	if chainCtx.TrustStatus.ErrorStatus != syscall.CERT_TRUST_NO_ERROR {
		status := chainCtx.TrustStatus.ErrorStatus
		switch status {
		case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
			return CertificateInvalidError{c, Expired}
		default:
			return UnknownAuthorityError{c}
		}
	}
	return nil
}

// checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
// use as a certificate chain for a SSL/TLS server.
func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
	sslPara := &syscall.SSLExtraCertChainPolicyPara{
		AuthType:   syscall.AUTHTYPE_SERVER,
		ServerName: syscall.StringToUTF16Ptr(opts.DNSName),
	}
	sslPara.Size = uint32(unsafe.Sizeof(*sslPara))

	para := &syscall.CertChainPolicyPara{
		ExtraPolicyPara: uintptr(unsafe.Pointer(sslPara)),
	}
	para.Size = uint32(unsafe.Sizeof(*para))

	status := syscall.CertChainPolicyStatus{}
	err := syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
	if err != nil {
		return err
	}

	// TODO(mkrautz): use the lChainIndex and lElementIndex fields
	// of the CertChainPolicyStatus to provide proper context, instead
	// using c.
	if status.Error != 0 {
		switch status.Error {
		case syscall.CERT_E_EXPIRED:
			return CertificateInvalidError{c, Expired}
		case syscall.CERT_E_CN_NO_MATCH:
			return HostnameError{c, opts.DNSName}
		case syscall.CERT_E_UNTRUSTEDROOT:
			return UnknownAuthorityError{c}
		default:
			return UnknownAuthorityError{c}
		}
	}

	return nil
}

// systemVerify is like Verify, except that it uses CryptoAPI calls
// to build certificate chains and verify them.
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
	hasDNSName := opts != nil && len(opts.DNSName) > 0

	storeCtx, err := createStoreContext(c, opts)
	if err != nil {
		return nil, err
	}
	defer syscall.CertFreeCertificateContext(storeCtx)

	para := new(syscall.CertChainPara)
	para.Size = uint32(unsafe.Sizeof(*para))

	// If there's a DNSName set in opts, assume we're verifying
	// a certificate from a TLS server.
	if hasDNSName {
		oids := []*byte{
			&syscall.OID_PKIX_KP_SERVER_AUTH[0],
			// Both IE and Chrome allow certificates with
			// Server Gated Crypto as well. Some certificates
			// in the wild require them.
			&syscall.OID_SERVER_GATED_CRYPTO[0],
			&syscall.OID_SGC_NETSCAPE[0],
		}
		para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
		para.RequestedUsage.Usage.Length = uint32(len(oids))
		para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
	} else {
		para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_AND
		para.RequestedUsage.Usage.Length = 0
		para.RequestedUsage.Usage.UsageIdentifiers = nil
	}

	var verifyTime *syscall.Filetime
	if opts != nil && !opts.CurrentTime.IsZero() {
		ft := syscall.NsecToFiletime(opts.CurrentTime.UnixNano())
		verifyTime = &ft
	}

	// CertGetCertificateChain will traverse Windows's root stores
	// in an attempt to build a verified certificate chain.  Once
	// it has found a verified chain, it stops. MSDN docs on
	// CERT_CHAIN_CONTEXT:
	//
	//   When a CERT_CHAIN_CONTEXT is built, the first simple chain
	//   begins with an end certificate and ends with a self-signed
	//   certificate. If that self-signed certificate is not a root
	//   or otherwise trusted certificate, an attempt is made to
	//   build a new chain. CTLs are used to create the new chain
	//   beginning with the self-signed certificate from the original
	//   chain as the end certificate of the new chain. This process
	//   continues building additional simple chains until the first
	//   self-signed certificate is a trusted certificate or until
	//   an additional simple chain cannot be built.
	//
	// The result is that we'll only get a single trusted chain to
	// return to our caller.
	var chainCtx *syscall.CertChainContext
	err = syscall.CertGetCertificateChain(syscall.Handle(0), storeCtx, verifyTime, storeCtx.Store, para, 0, 0, &chainCtx)
	if err != nil {
		return nil, err
	}
	defer syscall.CertFreeCertificateChain(chainCtx)

	err = checkChainTrustStatus(c, chainCtx)
	if err != nil {
		return nil, err
	}

	if hasDNSName {
		err = checkChainSSLServerPolicy(c, chainCtx, opts)
		if err != nil {
			return nil, err
		}
	}

	chain, err := extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount))
	if err != nil {
		return nil, err
	}

	chains = append(chains, chain)

	return chains, nil
}

func initSystemRoots() {
	systemRoots = NewCertPool()
}
<commit_msg>crypto/x509: do not forget to free cert context<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package x509

import (
	"errors"
	"syscall"
	"unsafe"
)

// Creates a new *syscall.CertContext representing the leaf certificate in an in-memory
// certificate store containing itself and all of the intermediate certificates specified
// in the opts.Intermediates CertPool.
//
// A pointer to the in-memory store is available in the returned CertContext's Store field.
// The store is automatically freed when the CertContext is freed using
// syscall.CertFreeCertificateContext.
func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertContext, error) {
	var storeCtx *syscall.CertContext

	leafCtx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &leaf.Raw[0], uint32(len(leaf.Raw)))
	if err != nil {
		return nil, err
	}
	defer syscall.CertFreeCertificateContext(leafCtx)

	handle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0)
	if err != nil {
		return nil, err
	}
	defer syscall.CertCloseStore(handle, 0)

	err = syscall.CertAddCertificateContextToStore(handle, leafCtx, syscall.CERT_STORE_ADD_ALWAYS, &storeCtx)
	if err != nil {
		return nil, err
	}

	if opts.Intermediates != nil {
		for _, intermediate := range opts.Intermediates.certs {
			ctx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &intermediate.Raw[0], uint32(len(intermediate.Raw)))
			if err != nil {
				return nil, err
			}

			err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
			syscall.CertFreeCertificateContext(ctx)
			if err != nil {
				return nil, err
			}
		}
	}

	return storeCtx, nil
}

// extractSimpleChain extracts the final certificate chain from a CertSimpleChain.
func extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*Certificate, err error) {
	if simpleChain == nil || count == 0 {
		return nil, errors.New("x509: invalid simple chain")
	}

	simpleChains := (*[1 << 20]*syscall.CertSimpleChain)(unsafe.Pointer(simpleChain))[:]
	lastChain := simpleChains[count-1]
	elements := (*[1 << 20]*syscall.CertChainElement)(unsafe.Pointer(lastChain.Elements))[:]
	for i := 0; i < int(lastChain.NumElements); i++ {
		// Copy the buf, since ParseCertificate does not create its own copy.
		cert := elements[i].CertContext
		encodedCert := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
		buf := make([]byte, cert.Length)
		copy(buf, encodedCert[:])
		parsedCert, err := ParseCertificate(buf)
		if err != nil {
			return nil, err
		}
		chain = append(chain, parsedCert)
	}

	return chain, nil
}

// checkChainTrustStatus checks the trust status of the certificate chain, translating
// any errors it finds into Go errors in the process.
func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error {
	if chainCtx.TrustStatus.ErrorStatus != syscall.CERT_TRUST_NO_ERROR {
		status := chainCtx.TrustStatus.ErrorStatus
		switch status {
		case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
			return CertificateInvalidError{c, Expired}
		default:
			return UnknownAuthorityError{c}
		}
	}
	return nil
}

// checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
// use as a certificate chain for a SSL/TLS server.
func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
	sslPara := &syscall.SSLExtraCertChainPolicyPara{
		AuthType:   syscall.AUTHTYPE_SERVER,
		ServerName: syscall.StringToUTF16Ptr(opts.DNSName),
	}
	sslPara.Size = uint32(unsafe.Sizeof(*sslPara))

	para := &syscall.CertChainPolicyPara{
		ExtraPolicyPara: uintptr(unsafe.Pointer(sslPara)),
	}
	para.Size = uint32(unsafe.Sizeof(*para))

	status := syscall.CertChainPolicyStatus{}
	err := syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
	if err != nil {
		return err
	}

	// TODO(mkrautz): use the lChainIndex and lElementIndex fields
	// of the CertChainPolicyStatus to provide proper context, instead
	// using c.
	if status.Error != 0 {
		switch status.Error {
		case syscall.CERT_E_EXPIRED:
			return CertificateInvalidError{c, Expired}
		case syscall.CERT_E_CN_NO_MATCH:
			return HostnameError{c, opts.DNSName}
		case syscall.CERT_E_UNTRUSTEDROOT:
			return UnknownAuthorityError{c}
		default:
			return UnknownAuthorityError{c}
		}
	}

	return nil
}

// systemVerify is like Verify, except that it uses CryptoAPI calls
// to build certificate chains and verify them.
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
	hasDNSName := opts != nil && len(opts.DNSName) > 0

	storeCtx, err := createStoreContext(c, opts)
	if err != nil {
		return nil, err
	}
	defer syscall.CertFreeCertificateContext(storeCtx)

	para := new(syscall.CertChainPara)
	para.Size = uint32(unsafe.Sizeof(*para))

	// If there's a DNSName set in opts, assume we're verifying
	// a certificate from a TLS server.
	if hasDNSName {
		oids := []*byte{
			&syscall.OID_PKIX_KP_SERVER_AUTH[0],
			// Both IE and Chrome allow certificates with
			// Server Gated Crypto as well. Some certificates
			// in the wild require them.
			&syscall.OID_SERVER_GATED_CRYPTO[0],
			&syscall.OID_SGC_NETSCAPE[0],
		}
		para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
		para.RequestedUsage.Usage.Length = uint32(len(oids))
		para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
	} else {
		para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_AND
		para.RequestedUsage.Usage.Length = 0
		para.RequestedUsage.Usage.UsageIdentifiers = nil
	}

	var verifyTime *syscall.Filetime
	if opts != nil && !opts.CurrentTime.IsZero() {
		ft := syscall.NsecToFiletime(opts.CurrentTime.UnixNano())
		verifyTime = &ft
	}

	// CertGetCertificateChain will traverse Windows's root stores
	// in an attempt to build a verified certificate chain.  Once
	// it has found a verified chain, it stops. MSDN docs on
	// CERT_CHAIN_CONTEXT:
	//
	//   When a CERT_CHAIN_CONTEXT is built, the first simple chain
	//   begins with an end certificate and ends with a self-signed
	//   certificate. If that self-signed certificate is not a root
	//   or otherwise trusted certificate, an attempt is made to
	//   build a new chain. CTLs are used to create the new chain
	//   beginning with the self-signed certificate from the original
	//   chain as the end certificate of the new chain. This process
	//   continues building additional simple chains until the first
	//   self-signed certificate is a trusted certificate or until
	//   an additional simple chain cannot be built.
	//
	// The result is that we'll only get a single trusted chain to
	// return to our caller.
	var chainCtx *syscall.CertChainContext
	err = syscall.CertGetCertificateChain(syscall.Handle(0), storeCtx, verifyTime, storeCtx.Store, para, 0, 0, &chainCtx)
	if err != nil {
		return nil, err
	}
	defer syscall.CertFreeCertificateChain(chainCtx)

	err = checkChainTrustStatus(c, chainCtx)
	if err != nil {
		return nil, err
	}

	if hasDNSName {
		err = checkChainSSLServerPolicy(c, chainCtx, opts)
		if err != nil {
			return nil, err
		}
	}

	chain, err := extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount))
	if err != nil {
		return nil, err
	}

	chains = append(chains, chain)

	return chains, nil
}

func initSystemRoots() {
	systemRoots = NewCertPool()
}
<|endoftext|>


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

/*
Package multipart implements MIME multipart parsing, as defined in RFC
2046.

The implementation is sufficient for HTTP (RFC 2388) and the multipart
bodies generated by popular browsers.
*/
package multipart

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"mime"
	"net/textproto"
)

// TODO(bradfitz): inline these once the compiler can inline them in
// read-only situation (such as bytes.HasSuffix)
var lf = []byte("\n")
var crlf = []byte("\r\n")

var emptyParams = make(map[string]string)

// A Part represents a single part in a multipart body.
type Part struct {
	// The headers of the body, if any, with the keys canonicalized
	// in the same fashion that the Go http.Request headers are.
	// i.e. "foo-bar" changes case to "Foo-Bar"
	Header textproto.MIMEHeader

	buffer *bytes.Buffer
	mr     *Reader

	disposition       string
	dispositionParams map[string]string
}

// FormName returns the name parameter if p has a Content-Disposition
// of type "form-data".  Otherwise it returns the empty string.
func (p *Part) FormName() string {
	// See http://tools.ietf.org/html/rfc2183 section 2 for EBNF
	// of Content-Disposition value format.
	if p.dispositionParams == nil {
		p.parseContentDisposition()
	}
	if p.disposition != "form-data" {
		return ""
	}
	return p.dispositionParams["name"]
}

// FileName returns the filename parameter of the Part's
// Content-Disposition header.
func (p *Part) FileName() string {
	if p.dispositionParams == nil {
		p.parseContentDisposition()
	}
	return p.dispositionParams["filename"]
}

func (p *Part) parseContentDisposition() {
	v := p.Header.Get("Content-Disposition")
	var err error
	p.disposition, p.dispositionParams, err = mime.ParseMediaType(v)
	if err != nil {
		p.dispositionParams = emptyParams
	}
}

// NewReader creates a new multipart Reader reading from r using the
// given MIME boundary.
func NewReader(reader io.Reader, boundary string) *Reader {
	b := []byte("\r\n--" + boundary + "--")
	return &Reader{
		bufReader: bufio.NewReader(reader),

		nl:               b[:2],
		nlDashBoundary:   b[:len(b)-2],
		dashBoundaryDash: b[2:],
		dashBoundary:     b[2 : len(b)-2],
	}
}

func newPart(mr *Reader) (*Part, error) {
	bp := &Part{
		Header: make(map[string][]string),
		mr:     mr,
		buffer: new(bytes.Buffer),
	}
	if err := bp.populateHeaders(); err != nil {
		return nil, err
	}
	return bp, nil
}

func (bp *Part) populateHeaders() error {
	r := textproto.NewReader(bp.mr.bufReader)
	header, err := r.ReadMIMEHeader()
	if err == nil {
		bp.Header = header
	}
	return err
}

// Read reads the body of a part, after its headers and before the
// next part (if any) begins.
func (p *Part) Read(d []byte) (n int, err error) {
	if p.buffer.Len() >= len(d) {
		// Internal buffer of unconsumed data is large enough for
		// the read request.  No need to parse more at the moment.
		return p.buffer.Read(d)
	}
	peek, err := p.mr.bufReader.Peek(4096) // TODO(bradfitz): add buffer size accessor
	unexpectedEof := err == io.EOF
	if err != nil && !unexpectedEof {
		return 0, fmt.Errorf("multipart: Part Read: %v", err)
	}
	if peek == nil {
		panic("nil peek buf")
	}

	// Search the peek buffer for "\r\n--boundary". If found,
	// consume everything up to the boundary. If not, consume only
	// as much of the peek buffer as cannot hold the boundary
	// string.
	nCopy := 0
	foundBoundary := false
	if idx := bytes.Index(peek, p.mr.nlDashBoundary); idx != -1 {
		nCopy = idx
		foundBoundary = true
	} else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 {
		nCopy = safeCount
	} else if unexpectedEof {
		// If we've run out of peek buffer and the boundary
		// wasn't found (and can't possibly fit), we must have
		// hit the end of the file unexpectedly.
		return 0, io.ErrUnexpectedEOF
	}
	if nCopy > 0 {
		if _, err := io.CopyN(p.buffer, p.mr.bufReader, int64(nCopy)); err != nil {
			return 0, err
		}
	}
	n, err = p.buffer.Read(d)
	if err == io.EOF && !foundBoundary {
		// If the boundary hasn't been reached there's more to
		// read, so don't pass through an EOF from the buffer
		err = nil
	}
	return
}

func (p *Part) Close() error {
	io.Copy(ioutil.Discard, p)
	return nil
}

// Reader is an iterator over parts in a MIME multipart body.
// Reader's underlying parser consumes its input as needed.  Seeking
// isn't supported.
type Reader struct {
	bufReader *bufio.Reader

	currentPart *Part
	partsRead   int

	nl, nlDashBoundary, dashBoundaryDash, dashBoundary []byte
}

// NextPart returns the next part in the multipart or an error.
// When there are no more parts, the error io.EOF is returned.
func (r *Reader) NextPart() (*Part, error) {
	if r.currentPart != nil {
		r.currentPart.Close()
	}

	expectNewPart := false
	for {
		line, err := r.bufReader.ReadSlice('\n')
		if err != nil {
			return nil, fmt.Errorf("multipart: NextPart: %v", err)
		}

		if r.isBoundaryDelimiterLine(line) {
			r.partsRead++
			bp, err := newPart(r)
			if err != nil {
				return nil, err
			}
			r.currentPart = bp
			return bp, nil
		}

		if hasPrefixThenNewline(line, r.dashBoundaryDash) {
			// Expected EOF
			return nil, io.EOF
		}

		if expectNewPart {
			return nil, fmt.Errorf("multipart: expecting a new Part; got line %q", string(line))
		}

		if r.partsRead == 0 {
			// skip line
			continue
		}

		// Consume the "\n" or "\r\n" separator between the
		// body of the previous part and the boundary line we
		// now expect will follow. (either a new part or the
		// end boundary)
		if bytes.Equal(line, r.nl) {
			expectNewPart = true
			continue
		}

		return nil, fmt.Errorf("multipart: unexpected line in Next(): %q", line)
	}
	panic("unreachable")
}

func (mr *Reader) isBoundaryDelimiterLine(line []byte) bool {
	// http://tools.ietf.org/html/rfc2046#section-5.1
	//   The boundary delimiter line is then defined as a line
	//   consisting entirely of two hyphen characters ("-",
	//   decimal value 45) followed by the boundary parameter
	//   value from the Content-Type header field, optional linear
	//   whitespace, and a terminating CRLF.
	if !bytes.HasPrefix(line, mr.dashBoundary) {
		return false
	}
	if bytes.HasSuffix(line, mr.nl) {
		return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-len(mr.nl)])
	}
	// Violate the spec and also support newlines without the
	// carriage return...
	if mr.partsRead == 0 && bytes.HasSuffix(line, lf) {
		if onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-1]) {
			mr.nl = mr.nl[1:]
			mr.nlDashBoundary = mr.nlDashBoundary[1:]
			return true
		}
	}
	return false
}

func onlyHorizontalWhitespace(s []byte) bool {
	for _, b := range s {
		if b != ' ' && b != '\t' {
			return false
		}
	}
	return true
}

func hasPrefixThenNewline(s, prefix []byte) bool {
	return bytes.HasPrefix(s, prefix) &&
		(len(s) == len(prefix)+1 && s[len(s)-1] == '\n' ||
			len(s) == len(prefix)+2 && bytes.HasSuffix(s, crlf))
}
<commit_msg>mulitpart bugfix (for swfupload)<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

/*
Package multipart implements MIME multipart parsing, as defined in RFC
2046.

The implementation is sufficient for HTTP (RFC 2388) and the multipart
bodies generated by popular browsers.
*/
package multipart

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"mime"
	"net/textproto"
)

// TODO(bradfitz): inline these once the compiler can inline them in
// read-only situation (such as bytes.HasSuffix)
var lf = []byte("\n")
var crlf = []byte("\r\n")

var emptyParams = make(map[string]string)

// A Part represents a single part in a multipart body.
type Part struct {
	// The headers of the body, if any, with the keys canonicalized
	// in the same fashion that the Go http.Request headers are.
	// i.e. "foo-bar" changes case to "Foo-Bar"
	Header textproto.MIMEHeader

	buffer *bytes.Buffer
	mr     *Reader

	disposition       string
	dispositionParams map[string]string
}

// FormName returns the name parameter if p has a Content-Disposition
// of type "form-data".  Otherwise it returns the empty string.
func (p *Part) FormName() string {
	// See http://tools.ietf.org/html/rfc2183 section 2 for EBNF
	// of Content-Disposition value format.
	if p.dispositionParams == nil {
		p.parseContentDisposition()
	}
	if p.disposition != "form-data" {
		return ""
	}
	return p.dispositionParams["name"]
}

// FileName returns the filename parameter of the Part's
// Content-Disposition header.
func (p *Part) FileName() string {
	if p.dispositionParams == nil {
		p.parseContentDisposition()
	}
	return p.dispositionParams["filename"]
}

func (p *Part) parseContentDisposition() {
	v := p.Header.Get("Content-Disposition")
	var err error
	p.disposition, p.dispositionParams, err = mime.ParseMediaType(v)
	if err != nil {
		p.dispositionParams = emptyParams
	}
}

// NewReader creates a new multipart Reader reading from r using the
// given MIME boundary.
func NewReader(reader io.Reader, boundary string) *Reader {
	b := []byte("\r\n--" + boundary + "--")
	return &Reader{
		bufReader: bufio.NewReader(reader),

		nl:               b[:2],
		nlDashBoundary:   b[:len(b)-2],
		dashBoundaryDash: b[2:],
		dashBoundary:     b[2 : len(b)-2],
	}
}

func newPart(mr *Reader) (*Part, error) {
	bp := &Part{
		Header: make(map[string][]string),
		mr:     mr,
		buffer: new(bytes.Buffer),
	}
	if err := bp.populateHeaders(); err != nil {
		return nil, err
	}
	return bp, nil
}

func (bp *Part) populateHeaders() error {
	r := textproto.NewReader(bp.mr.bufReader)
	header, err := r.ReadMIMEHeader()
	if err == nil {
		bp.Header = header
	}
	return err
}

// Read reads the body of a part, after its headers and before the
// next part (if any) begins.
func (p *Part) Read(d []byte) (n int, err error) {
	if p.buffer.Len() >= len(d) {
		// Internal buffer of unconsumed data is large enough for
		// the read request.  No need to parse more at the moment.
		return p.buffer.Read(d)
	}
	peek, err := p.mr.bufReader.Peek(4096) // TODO(bradfitz): add buffer size accessor
	unexpectedEof := err == io.EOF
	if err != nil && !unexpectedEof {
		return 0, fmt.Errorf("multipart: Part Read: %v", err)
	}
	if peek == nil {
		panic("nil peek buf")
	}

	// Search the peek buffer for "\r\n--boundary". If found,
	// consume everything up to the boundary. If not, consume only
	// as much of the peek buffer as cannot hold the boundary
	// string.
	nCopy := 0
	foundBoundary := false
	if idx := bytes.Index(peek, p.mr.nlDashBoundary); idx != -1 {
		nCopy = idx
		foundBoundary = true
	} else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 {
		nCopy = safeCount
	} else if unexpectedEof {
		// If we've run out of peek buffer and the boundary
		// wasn't found (and can't possibly fit), we must have
		// hit the end of the file unexpectedly.
		return 0, io.ErrUnexpectedEOF
	}
	if nCopy > 0 {
		if _, err := io.CopyN(p.buffer, p.mr.bufReader, int64(nCopy)); err != nil {
			return 0, err
		}
	}
	n, err = p.buffer.Read(d)
	if err == io.EOF && !foundBoundary {
		// If the boundary hasn't been reached there's more to
		// read, so don't pass through an EOF from the buffer
		err = nil
	}
	return
}

func (p *Part) Close() error {
	io.Copy(ioutil.Discard, p)
	return nil
}

// Reader is an iterator over parts in a MIME multipart body.
// Reader's underlying parser consumes its input as needed.  Seeking
// isn't supported.
type Reader struct {
	bufReader *bufio.Reader

	currentPart *Part
	partsRead   int

	nl, nlDashBoundary, dashBoundaryDash, dashBoundary []byte
}

// NextPart returns the next part in the multipart or an error.
// When there are no more parts, the error io.EOF is returned.
func (r *Reader) NextPart() (*Part, error) {
	if r.currentPart != nil {
		r.currentPart.Close()
	}

	expectNewPart := false
	for {
		line, err := r.bufReader.ReadSlice('\n')
		if err != nil {
			return nil, io.EOF // fmt.Errorf("multipart: NextPart: %v", err)
		}

		if r.isBoundaryDelimiterLine(line) {
			r.partsRead++
			bp, err := newPart(r)
			if err != nil {
				return nil, err
			}
			r.currentPart = bp
			return bp, nil
		}

		if hasPrefixThenNewline(line, r.dashBoundaryDash) {
			// Expected EOF
			return nil, io.EOF
		}

		if expectNewPart {
			return nil, fmt.Errorf("multipart: expecting a new Part; got line %q", string(line))
		}

		if r.partsRead == 0 {
			// skip line
			continue
		}

		// Consume the "\n" or "\r\n" separator between the
		// body of the previous part and the boundary line we
		// now expect will follow. (either a new part or the
		// end boundary)
		if bytes.Equal(line, r.nl) {
			expectNewPart = true
			continue
		}

		return nil, fmt.Errorf("multipart: unexpected line in Next(): %q", line)
	}
	panic("unreachable")
}

func (mr *Reader) isBoundaryDelimiterLine(line []byte) bool {
	// http://tools.ietf.org/html/rfc2046#section-5.1
	//   The boundary delimiter line is then defined as a line
	//   consisting entirely of two hyphen characters ("-",
	//   decimal value 45) followed by the boundary parameter
	//   value from the Content-Type header field, optional linear
	//   whitespace, and a terminating CRLF.
	if !bytes.HasPrefix(line, mr.dashBoundary) {
		return false
	}
	if bytes.HasSuffix(line, mr.nl) {
		return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-len(mr.nl)])
	}
	// Violate the spec and also support newlines without the
	// carriage return...
	if mr.partsRead == 0 && bytes.HasSuffix(line, lf) {
		if onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-1]) {
			mr.nl = mr.nl[1:]
			mr.nlDashBoundary = mr.nlDashBoundary[1:]
			return true
		}
	}
	return false
}

func onlyHorizontalWhitespace(s []byte) bool {
	for _, b := range s {
		if b != ' ' && b != '\t' {
			return false
		}
	}
	return true
}

func hasPrefixThenNewline(s, prefix []byte) bool {
	return bytes.HasPrefix(s, prefix) &&
		(len(s) == len(prefix)+1 && s[len(s)-1] == '\n' ||
			len(s) == len(prefix)+2 && bytes.HasSuffix(s, crlf))
}
<|endoftext|>


<commit_before>package messaging

import (
	"testing"
	"os"
	"runtime"
)

var queueConnParams = ConnParams{
	"localhost","3333","tcp",
}

func init() {
	runtime.LockOSThread()
}

func TestMain(m *testing.M) {
	go func() {
		os.Exit(m.Run())
	}()
	var queue = NewQueue(queueConnParams)
	queue.Run()
}

func TestConnectingToQueue(t *testing.T) {
	var node = NewNode(queueConnParams)
	err := node.Run()
	if err != nil {
		t.Fail()
	}
}

func TestSendingToQueue(t *testing.T) {
	var node = NewNode(queueConnParams)
	err := node.Run()
	if err != nil {
		t.Fail()
	}
	node.SendMessage("Hello world!")
}

func TestCloseNode(t *testing.T) {
	var node = NewNode(queueConnParams)
	err := node.Run()
	if err != nil {
		t.Fail()
	}
	close_err := node.CloseConn()
	if close_err != nil {
		t.Fail()
	}
}
<commit_msg>Messaging unit tests fixed.<commit_after>package messaging

import (
	"testing"
	"os"
	"runtime"
	"github.com/google/uuid"
)

var queueConnParams = ConnParams{
	"localhost","3333","tcp",
}

func init() {
	runtime.LockOSThread()
}

func TestMain(m *testing.M) {
	go func() {
		os.Exit(m.Run())
	}()
	var queue = NewQueue(queueConnParams)
	queue.Run()
}

func TestConnectingToQueue(t *testing.T) {
	var node = NewNode(queueConnParams)
	err := node.Run()
	if err != nil {
		t.Fail()
	}
}

func TestSendingToQueue(t *testing.T) {
	var node = NewNode(queueConnParams)
	err := node.Run()
	if err != nil {
		t.Fail()
	}
	var message = Message{Key:uuid.New(), Topic:"Test", Text:"Hello world!"}
	node.SendMessage(message)
}

func TestCloseNode(t *testing.T) {
	var node = NewNode(queueConnParams)
	err := node.Run()
	if err != nil {
		t.Fail()
	}
	close_err := node.CloseConn()
	if close_err != nil {
		t.Fail()
	}
}
<|endoftext|>


<commit_before>package ecs

import (
	"testing"
)

func TestDisks(t *testing.T) {

	client := NewTestClient()

	instance, err := client.DescribeInstanceAttribute(TestInstanceId)
	if err != nil {
		t.Fatalf("Failed to DescribeInstanceAttribute for instance %s: %v", TestInstanceId, err)
	}

	args := DescribeDisksArgs{}

	args.InstanceId = TestInstanceId
	args.RegionId = instance.RegionId
	disks, _, err := client.DescribeDisks(&args)

	if err != nil {
		t.Fatalf("Failed to DescribeDisks for instance %s: %v", TestInstanceId, err)
	}

	for _, disk := range disks {
		t.Logf("Disk of instance %s: %++v", TestInstanceId, disk)
	}
}

func TestDiskCreationAndDeletion(t *testing.T) {

	if TestIAmRich == false { //Avoid payment
		return
	}

	client := NewTestClient()

	instance, err := client.DescribeInstanceAttribute(TestInstanceId)
	if err != nil {
		t.Fatalf("Failed to DescribeInstanceAttribute for instance %s: %v", TestInstanceId, err)
	}

	args := CreateDiskArgs{
		RegionId: instance.RegionId,
		ZoneId:   instance.ZoneId,
		DiskName: "test-disk",
		Size:     5,
	}

	diskId, err := client.CreateDisk(&args)
	if err != nil {
		t.Fatalf("Failed to create disk: %v", err)
	}
	t.Logf("Create disk %s successfully", diskId)

	attachArgs := AttachDiskArgs{
		InstanceId: instance.InstanceId,
		DiskId:     diskId,
	}

	err = client.AttachDisk(&attachArgs)
	if err != nil {
		t.Errorf("Failed to create disk: %v", err)
	} else {
		t.Logf("Attach disk %s to instance %s successfully", diskId, instance.InstanceId)

		instance, err = client.DescribeInstanceAttribute(TestInstanceId)
		if err != nil {
			t.Errorf("Failed to DescribeInstanceAttribute for instance %s: %v", TestInstanceId, err)
		} else {
			t.Logf("Instance: %++v  %v", instance, err)
		}
		err = client.WaitForDisk(instance.RegionId, diskId, DiskStatusInUse, 0)
		if err != nil {
			t.Fatalf("Failed to wait for disk %s to status %s: %v", diskId, DiskStatusInUse, err)
		}
		err = client.DetachDisk(instance.InstanceId, diskId)
		if err != nil {
			t.Errorf("Failed to detach disk: %v", err)
		} else {
			t.Logf("Detach disk %s to instance %s successfully", diskId, instance.InstanceId)
		}

		err = client.WaitForDisk(instance.RegionId, diskId, DiskStatusAvailable, 0)
		if err != nil {
			t.Fatalf("Failed to wait for disk %s to status %s: %v", diskId, DiskStatusAvailable, err)
		}
	}
	err = client.DeleteDisk(diskId)
	if err != nil {
		t.Fatalf("Failed to delete disk %s: %v", diskId, err)
	}
	t.Logf("Delete disk %s successfully", diskId)
}

func TestReplaceSystemDisk(t *testing.T) {
	client := NewTestClient()

	err := client.WaitForInstance(TestInstanceId, Running, 0)
	err = client.StopInstance(TestInstanceId, true)
	if err != nil {
		t.Errorf("Failed to stop instance %s: %v", TestInstanceId, err)
	}
	err = client.WaitForInstance(TestInstanceId, Stopped, 0)
	if err != nil {
		t.Errorf("Instance %s is failed to stop: %v", TestInstanceId, err)
	}
	t.Logf("Instance %s is stopped successfully.", TestInstanceId)

	args := ReplaceSystemDiskArgs{
		InstanceId: TestInstanceId,
		ImageId:    TestImageId,
	}

	diskId, err := client.ReplaceSystemDisk(&args)
	if err != nil {
		t.Errorf("Failed to replace system disk %v", err)
	}
	err = client.WaitForInstance(TestInstanceId, Stopped, 60)
	err = client.StartInstance(TestInstanceId)
	if err != nil {
		t.Errorf("Failed to start instance %s: %v", TestInstanceId, err)
	} else {
		err = client.WaitForInstance(TestInstanceId, Running, 0)
		if err != nil {
			t.Errorf("Failed to wait for instance %s running: %v", TestInstanceId, err)
		}
	}
	t.Logf("Replace system disk %s successfully ", diskId)
}
<commit_msg>add new test case<commit_after>package ecs

import (
	"testing"
)

func TestDisks(t *testing.T) {

	client := NewTestClient()

	instance, err := client.DescribeInstanceAttribute(TestInstanceId)
	if err != nil {
		t.Fatalf("Failed to DescribeInstanceAttribute for instance %s: %v", TestInstanceId, err)
	}

	args := DescribeDisksArgs{}

	args.InstanceId = TestInstanceId
	args.RegionId = instance.RegionId
	disks, _, err := client.DescribeDisks(&args)

	if err != nil {
		t.Fatalf("Failed to DescribeDisks for instance %s: %v", TestInstanceId, err)
	}

	for _, disk := range disks {
		t.Logf("Disk of instance %s: %++v", TestInstanceId, disk)
	}
}

func TestDiskCreationAndDeletion(t *testing.T) {

	if TestIAmRich == false { //Avoid payment
		return
	}

	client := NewTestClient()

	instance, err := client.DescribeInstanceAttribute(TestInstanceId)
	if err != nil {
		t.Fatalf("Failed to DescribeInstanceAttribute for instance %s: %v", TestInstanceId, err)
	}

	args := CreateDiskArgs{
		RegionId: instance.RegionId,
		ZoneId:   instance.ZoneId,
		DiskName: "test-disk",
		Size:     5,
	}

	diskId, err := client.CreateDisk(&args)
	if err != nil {
		t.Fatalf("Failed to create disk: %v", err)
	}
	t.Logf("Create disk %s successfully", diskId)

	attachArgs := AttachDiskArgs{
		InstanceId: instance.InstanceId,
		DiskId:     diskId,
	}

	err = client.AttachDisk(&attachArgs)
	if err != nil {
		t.Errorf("Failed to create disk: %v", err)
	} else {
		t.Logf("Attach disk %s to instance %s successfully", diskId, instance.InstanceId)

		instance, err = client.DescribeInstanceAttribute(TestInstanceId)
		if err != nil {
			t.Errorf("Failed to DescribeInstanceAttribute for instance %s: %v", TestInstanceId, err)
		} else {
			t.Logf("Instance: %++v  %v", instance, err)
		}
		err = client.WaitForDisk(instance.RegionId, diskId, DiskStatusInUse, 0)
		if err != nil {
			t.Fatalf("Failed to wait for disk %s to status %s: %v", diskId, DiskStatusInUse, err)
		}
		err = client.DetachDisk(instance.InstanceId, diskId)
		if err != nil {
			t.Errorf("Failed to detach disk: %v", err)
		} else {
			t.Logf("Detach disk %s to instance %s successfully", diskId, instance.InstanceId)
		}

		err = client.WaitForDisk(instance.RegionId, diskId, DiskStatusAvailable, 0)
		if err != nil {
			t.Fatalf("Failed to wait for disk %s to status %s: %v", diskId, DiskStatusAvailable, err)
		}
	}
	err = client.DeleteDisk(diskId)
	if err != nil {
		t.Fatalf("Failed to delete disk %s: %v", diskId, err)
	}
	t.Logf("Delete disk %s successfully", diskId)
}

func TestReplaceSystemDisk222(t *testing.T) {
	client := NewTestClientForDebug()

	args := ReplaceSystemDiskArgs{
		InstanceId: TestInstanceId,
		ImageId:    TestImageId,
		SystemDisk: SystemDiskType{
			Size: 192,
		},
		ClientToken: client.GenerateClientToken(),
	}

	diskId, err := client.ReplaceSystemDisk(&args)
	if err != nil {
		t.Errorf("Failed to replace system disk %v", err)
	} else {
		t.Logf("diskId is %s", diskId)
	}
}

func TestReplaceSystemDisk(t *testing.T) {
	client := NewTestClient()

	err := client.WaitForInstance(TestInstanceId, Running, 0)
	err = client.StopInstance(TestInstanceId, true)
	if err != nil {
		t.Errorf("Failed to stop instance %s: %v", TestInstanceId, err)
	}
	err = client.WaitForInstance(TestInstanceId, Stopped, 0)
	if err != nil {
		t.Errorf("Instance %s is failed to stop: %v", TestInstanceId, err)
	}
	t.Logf("Instance %s is stopped successfully.", TestInstanceId)

	args := ReplaceSystemDiskArgs{
		InstanceId: TestInstanceId,
		ImageId:    TestImageId,
	}

	diskId, err := client.ReplaceSystemDisk(&args)
	if err != nil {
		t.Errorf("Failed to replace system disk %v", err)
	}
	err = client.WaitForInstance(TestInstanceId, Stopped, 60)
	err = client.StartInstance(TestInstanceId)
	if err != nil {
		t.Errorf("Failed to start instance %s: %v", TestInstanceId, err)
	} else {
		err = client.WaitForInstance(TestInstanceId, Running, 0)
		if err != nil {
			t.Errorf("Failed to wait for instance %s running: %v", TestInstanceId, err)
		}
	}
	t.Logf("Replace system disk %s successfully ", diskId)
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2015, b3log.org
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package editor includes editor related manipulations.
package editor

import (
	"bytes"
	"encoding/json"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/b3log/wide/conf"
	"github.com/b3log/wide/file"
	"github.com/b3log/wide/log"
	"github.com/b3log/wide/session"
	"github.com/b3log/wide/util"
	"github.com/gorilla/websocket"
)

// Logger.
var logger = log.NewLogger(os.Stdout)

// WSHandler handles request of creating editor channel.
// XXX: NOT used at present
func WSHandler(w http.ResponseWriter, r *http.Request) {
	httpSession, _ := session.HTTPSession.Get(r, "wide-session")
	if httpSession.IsNew {
		http.Error(w, "Forbidden", http.StatusForbidden)

		return
	}

	sid := httpSession.Values["id"].(string)

	conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024)
	editorChan := util.WSChannel{Sid: sid, Conn: conn, Request: r, Time: time.Now()}

	ret := map[string]interface{}{"output": "Editor initialized", "cmd": "init-editor"}
	err := editorChan.WriteJSON(&ret)
	if nil != err {
		return
	}

	session.EditorWS[sid] = &editorChan

	logger.Tracef("Open a new [Editor] with session [%s], %d", sid, len(session.EditorWS))

	args := map[string]interface{}{}
	for {
		if err := session.EditorWS[sid].ReadJSON(&args); err != nil {
			return
		}

		code := args["code"].(string)
		line := int(args["cursorLine"].(float64))
		ch := int(args["cursorCh"].(float64))

		offset := getCursorOffset(code, line, ch)

		logger.Tracef("offset: %d", offset)

		gocode := util.Go.GetExecutableInGOBIN("gocode")
		argv := []string{"-f=json", "autocomplete", strconv.Itoa(offset)}

		var output bytes.Buffer

		cmd := exec.Command(gocode, argv...)
		cmd.Stdout = &output

		stdin, _ := cmd.StdinPipe()
		cmd.Start()
		stdin.Write([]byte(code))
		stdin.Close()
		cmd.Wait()

		ret = map[string]interface{}{"output": string(output.Bytes()), "cmd": "autocomplete"}

		if err := session.EditorWS[sid].WriteJSON(&ret); err != nil {
			logger.Error("Editor WS ERROR: " + err.Error())
			return
		}
	}
}

// AutocompleteHandler handles request of code autocompletion.
func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
	var args map[string]interface{}

	if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	session, _ := session.HTTPSession.Get(r, "wide-session")
	if session.IsNew {
		http.Error(w, "Forbidden", http.StatusForbidden)

		return
	}
	username := session.Values["username"].(string)

	path := args["path"].(string)

	fout, err := os.Create(path)

	if nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	code := args["code"].(string)
	fout.WriteString(code)

	if err := fout.Close(); nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	line := int(args["cursorLine"].(float64))
	ch := int(args["cursorCh"].(float64))

	offset := getCursorOffset(code, line, ch)

	logger.Tracef("offset: %d", offset)

	userWorkspace := conf.GetUserWorkspace(username)
	workspaces := filepath.SplitList(userWorkspace)
	libPath := ""
	for _, workspace := range workspaces {
		userLib := workspace + conf.PathSeparator + "pkg" + conf.PathSeparator +
			runtime.GOOS + "_" + runtime.GOARCH
		libPath += userLib + conf.PathListSeparator
	}

	logger.Tracef("gocode set lib-path [%s]", libPath)

	// FIXME: using gocode set lib-path has some issues while accrossing workspaces
	gocode := util.Go.GetExecutableInGOBIN("gocode")
	argv := []string{"set", "lib-path", libPath}
	exec.Command(gocode, argv...).Run()

	argv = []string{"-f=json", "autocomplete", strconv.Itoa(offset)}
	cmd := exec.Command(gocode, argv...)

	stdin, _ := cmd.StdinPipe()
	stdin.Write([]byte(code))
	stdin.Close()

	output, err := cmd.CombinedOutput()
	if nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(output)
}

// GetExprInfoHandler handles request of getting expression infomation.
func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
	data := map[string]interface{}{"succ": true}
	defer util.RetJSON(w, r, data)

	session, _ := session.HTTPSession.Get(r, "wide-session")
	username := session.Values["username"].(string)

	var args map[string]interface{}
	if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	path := args["path"].(string)
	curDir := path[:strings.LastIndex(path, conf.PathSeparator)]
	filename := path[strings.LastIndex(path, conf.PathSeparator)+1:]

	fout, err := os.Create(path)

	if nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	code := args["code"].(string)
	fout.WriteString(code)

	if err := fout.Close(); nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	line := int(args["cursorLine"].(float64))
	ch := int(args["cursorCh"].(float64))

	offset := getCursorOffset(code, line, ch)

	logger.Tracef("offset [%d]", offset)

	ideStub := util.Go.GetExecutableInGOBIN("ide_stub")
	argv := []string{"type", "-cursor", filename + ":" + strconv.Itoa(offset), "-info", "."}
	cmd := exec.Command(ideStub, argv...)
	cmd.Dir = curDir

	setCmdEnv(cmd, username)

	output, err := cmd.CombinedOutput()
	if nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	exprInfo := strings.TrimSpace(string(output))
	if "" == exprInfo {
		data["succ"] = false

		return
	}

	data["info"] = exprInfo
}

// FindDeclarationHandler handles request of finding declaration.
func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
	data := map[string]interface{}{"succ": true}
	defer util.RetJSON(w, r, data)

	session, _ := session.HTTPSession.Get(r, "wide-session")
	if session.IsNew {
		http.Error(w, "Forbidden", http.StatusForbidden)

		return
	}
	username := session.Values["username"].(string)

	var args map[string]interface{}
	if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	path := args["path"].(string)
	curDir := path[:strings.LastIndex(path, conf.PathSeparator)]
	filename := path[strings.LastIndex(path, conf.PathSeparator)+1:]

	fout, err := os.Create(path)

	if nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	code := args["code"].(string)
	fout.WriteString(code)

	if err := fout.Close(); nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	line := int(args["cursorLine"].(float64))
	ch := int(args["cursorCh"].(float64))

	offset := getCursorOffset(code, line, ch)

	logger.Tracef("offset [%d]", offset)

	ideStub := util.Go.GetExecutableInGOBIN("ide_stub")
	argv := []string{"type", "-cursor", filename + ":" + strconv.Itoa(offset), "-def", "."}
	cmd := exec.Command(ideStub, argv...)
	cmd.Dir = curDir

	setCmdEnv(cmd, username)

	output, err := cmd.CombinedOutput()
	if nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	found := strings.TrimSpace(string(output))
	if "" == found {
		data["succ"] = false

		return
	}

	part := found[:strings.LastIndex(found, ":")]
	cursorSep := strings.LastIndex(part, ":")
	path = found[:cursorSep]
	cursorLine, _ := strconv.Atoi(found[cursorSep+1 : strings.LastIndex(found, ":")])
	cursorCh, _ := strconv.Atoi(found[strings.LastIndex(found, ":")+1:])

	data["path"] = path
	data["cursorLine"] = cursorLine
	data["cursorCh"] = cursorCh
}

// FindUsagesHandler handles request of finding usages.
func FindUsagesHandler(w http.ResponseWriter, r *http.Request) {
	data := map[string]interface{}{"succ": true}
	defer util.RetJSON(w, r, data)

	session, _ := session.HTTPSession.Get(r, "wide-session")
	if session.IsNew {
		http.Error(w, "Forbidden", http.StatusForbidden)

		return
	}
	username := session.Values["username"].(string)

	var args map[string]interface{}

	if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	filePath := args["path"].(string)
	curDir := filePath[:strings.LastIndex(filePath, conf.PathSeparator)]
	filename := filePath[strings.LastIndex(filePath, conf.PathSeparator)+1:]

	fout, err := os.Create(filePath)

	if nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	code := args["code"].(string)
	fout.WriteString(code)

	if err := fout.Close(); nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	line := int(args["cursorLine"].(float64))
	ch := int(args["cursorCh"].(float64))

	offset := getCursorOffset(code, line, ch)
	logger.Tracef("offset [%d]", offset)

	ideStub := util.Go.GetExecutableInGOBIN("ide_stub")
	argv := []string{"type", "-cursor", filename + ":" + strconv.Itoa(offset), "-use", "."}
	cmd := exec.Command(ideStub, argv...)
	cmd.Dir = curDir

	setCmdEnv(cmd, username)

	output, err := cmd.CombinedOutput()
	if nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	result := strings.TrimSpace(string(output))
	if "" == result {
		data["succ"] = false

		return
	}

	founds := strings.Split(result, "\n")
	usages := []*file.Snippet{}
	for _, found := range founds {
		found = strings.TrimSpace(found)

		part := found[:strings.LastIndex(found, ":")]
		cursorSep := strings.LastIndex(part, ":")
		path := found[:cursorSep]
		cursorLine, _ := strconv.Atoi(found[cursorSep+1 : strings.LastIndex(found, ":")])
		cursorCh, _ := strconv.Atoi(found[strings.LastIndex(found, ":")+1:])

		usage := &file.Snippet{Path: path, Line: cursorLine, Ch: cursorCh, Contents: []string{""}}
		usages = append(usages, usage)
	}

	data["founds"] = usages
}

// getCursorOffset calculates the cursor offset.
//
// line is the line number, starts with 0 that means the first line
// ch is the column number, starts with 0 that means the first column
func getCursorOffset(code string, line, ch int) (offset int) {
	lines := strings.Split(code, "\n")

	// calculate sum length of lines before
	for i := 0; i < line; i++ {
		offset += len(lines[i])
	}

	// calculate length of the current line and column
	curLine := lines[line]
	var buffer bytes.Buffer
	r := []rune(curLine)
	for i := 0; i < ch; i++ {
		buffer.WriteString(string(r[i]))
	}

	offset += len(buffer.String()) // append length of current line
	offset += line                 // append number of '\n'

	return offset
}

func setCmdEnv(cmd *exec.Cmd, username string) {
	userWorkspace := conf.GetUserWorkspace(username)

	cmd.Env = append(cmd.Env,
		"GOPATH="+userWorkspace,
		"GOOS="+runtime.GOOS,
		"GOARCH="+runtime.GOARCH,
		"GOROOT="+runtime.GOROOT(),
		"PATH="+os.Getenv("PATH"))
}
<commit_msg>fix #217<commit_after>// Copyright (c) 2014-2015, b3log.org
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package editor includes editor related manipulations.
package editor

import (
	"bytes"
	"encoding/json"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/b3log/wide/conf"
	"github.com/b3log/wide/file"
	"github.com/b3log/wide/log"
	"github.com/b3log/wide/session"
	"github.com/b3log/wide/util"
	"github.com/gorilla/websocket"
)

// Logger.
var logger = log.NewLogger(os.Stdout)

// WSHandler handles request of creating editor channel.
// XXX: NOT used at present
func WSHandler(w http.ResponseWriter, r *http.Request) {
	httpSession, _ := session.HTTPSession.Get(r, "wide-session")
	if httpSession.IsNew {
		http.Error(w, "Forbidden", http.StatusForbidden)

		return
	}

	sid := httpSession.Values["id"].(string)

	conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024)
	editorChan := util.WSChannel{Sid: sid, Conn: conn, Request: r, Time: time.Now()}

	ret := map[string]interface{}{"output": "Editor initialized", "cmd": "init-editor"}
	err := editorChan.WriteJSON(&ret)
	if nil != err {
		return
	}

	session.EditorWS[sid] = &editorChan

	logger.Tracef("Open a new [Editor] with session [%s], %d", sid, len(session.EditorWS))

	args := map[string]interface{}{}
	for {
		if err := session.EditorWS[sid].ReadJSON(&args); err != nil {
			return
		}

		code := args["code"].(string)
		line := int(args["cursorLine"].(float64))
		ch := int(args["cursorCh"].(float64))

		offset := getCursorOffset(code, line, ch)

		logger.Tracef("offset: %d", offset)

		gocode := util.Go.GetExecutableInGOBIN("gocode")
		argv := []string{"-f=json", "autocomplete", strconv.Itoa(offset)}

		var output bytes.Buffer

		cmd := exec.Command(gocode, argv...)
		cmd.Stdout = &output

		stdin, _ := cmd.StdinPipe()
		cmd.Start()
		stdin.Write([]byte(code))
		stdin.Close()
		cmd.Wait()

		ret = map[string]interface{}{"output": string(output.Bytes()), "cmd": "autocomplete"}

		if err := session.EditorWS[sid].WriteJSON(&ret); err != nil {
			logger.Error("Editor WS ERROR: " + err.Error())
			return
		}
	}
}

// AutocompleteHandler handles request of code autocompletion.
func AutocompleteHandler(w http.ResponseWriter, r *http.Request) {
	var args map[string]interface{}

	if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	session, _ := session.HTTPSession.Get(r, "wide-session")
	if session.IsNew {
		http.Error(w, "Forbidden", http.StatusForbidden)

		return
	}
	username := session.Values["username"].(string)

	path := args["path"].(string)

	fout, err := os.Create(path)

	if nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	code := args["code"].(string)
	fout.WriteString(code)

	if err := fout.Close(); nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	line := int(args["cursorLine"].(float64))
	ch := int(args["cursorCh"].(float64))

	offset := getCursorOffset(code, line, ch)

	logger.Tracef("offset: %d", offset)

	userWorkspace := conf.GetUserWorkspace(username)
	workspaces := filepath.SplitList(userWorkspace)
	libPath := ""
	for _, workspace := range workspaces {
		userLib := workspace + conf.PathSeparator + "pkg" + conf.PathSeparator +
			runtime.GOOS + "_" + runtime.GOARCH
		libPath += userLib + conf.PathListSeparator
	}

	logger.Tracef("gocode set lib-path [%s]", libPath)

	// FIXME: using gocode set lib-path has some issues while accrossing workspaces
	gocode := util.Go.GetExecutableInGOBIN("gocode")
	exec.Command(gocode, []string{"set", "lib-path", libPath}...).Run()

	argv := []string{"-f=json", "--in=" + path, "autocomplete", strconv.Itoa(offset)}
	cmd := exec.Command(gocode, argv...)

	output, err := cmd.CombinedOutput()
	if nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(output)
}

// GetExprInfoHandler handles request of getting expression infomation.
func GetExprInfoHandler(w http.ResponseWriter, r *http.Request) {
	data := map[string]interface{}{"succ": true}
	defer util.RetJSON(w, r, data)

	session, _ := session.HTTPSession.Get(r, "wide-session")
	username := session.Values["username"].(string)

	var args map[string]interface{}
	if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	path := args["path"].(string)
	curDir := path[:strings.LastIndex(path, conf.PathSeparator)]
	filename := path[strings.LastIndex(path, conf.PathSeparator)+1:]

	fout, err := os.Create(path)

	if nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	code := args["code"].(string)
	fout.WriteString(code)

	if err := fout.Close(); nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	line := int(args["cursorLine"].(float64))
	ch := int(args["cursorCh"].(float64))

	offset := getCursorOffset(code, line, ch)

	logger.Tracef("offset [%d]", offset)

	ideStub := util.Go.GetExecutableInGOBIN("ide_stub")
	argv := []string{"type", "-cursor", filename + ":" + strconv.Itoa(offset), "-info", "."}
	cmd := exec.Command(ideStub, argv...)
	cmd.Dir = curDir

	setCmdEnv(cmd, username)

	output, err := cmd.CombinedOutput()
	if nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	exprInfo := strings.TrimSpace(string(output))
	if "" == exprInfo {
		data["succ"] = false

		return
	}

	data["info"] = exprInfo
}

// FindDeclarationHandler handles request of finding declaration.
func FindDeclarationHandler(w http.ResponseWriter, r *http.Request) {
	data := map[string]interface{}{"succ": true}
	defer util.RetJSON(w, r, data)

	session, _ := session.HTTPSession.Get(r, "wide-session")
	if session.IsNew {
		http.Error(w, "Forbidden", http.StatusForbidden)

		return
	}
	username := session.Values["username"].(string)

	var args map[string]interface{}
	if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	path := args["path"].(string)
	curDir := path[:strings.LastIndex(path, conf.PathSeparator)]
	filename := path[strings.LastIndex(path, conf.PathSeparator)+1:]

	fout, err := os.Create(path)

	if nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	code := args["code"].(string)
	fout.WriteString(code)

	if err := fout.Close(); nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	line := int(args["cursorLine"].(float64))
	ch := int(args["cursorCh"].(float64))

	offset := getCursorOffset(code, line, ch)

	logger.Tracef("offset [%d]", offset)

	ideStub := util.Go.GetExecutableInGOBIN("ide_stub")
	argv := []string{"type", "-cursor", filename + ":" + strconv.Itoa(offset), "-def", "."}
	cmd := exec.Command(ideStub, argv...)
	cmd.Dir = curDir

	setCmdEnv(cmd, username)

	output, err := cmd.CombinedOutput()
	if nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	found := strings.TrimSpace(string(output))
	if "" == found {
		data["succ"] = false

		return
	}

	part := found[:strings.LastIndex(found, ":")]
	cursorSep := strings.LastIndex(part, ":")
	path = found[:cursorSep]
	cursorLine, _ := strconv.Atoi(found[cursorSep+1 : strings.LastIndex(found, ":")])
	cursorCh, _ := strconv.Atoi(found[strings.LastIndex(found, ":")+1:])

	data["path"] = path
	data["cursorLine"] = cursorLine
	data["cursorCh"] = cursorCh
}

// FindUsagesHandler handles request of finding usages.
func FindUsagesHandler(w http.ResponseWriter, r *http.Request) {
	data := map[string]interface{}{"succ": true}
	defer util.RetJSON(w, r, data)

	session, _ := session.HTTPSession.Get(r, "wide-session")
	if session.IsNew {
		http.Error(w, "Forbidden", http.StatusForbidden)

		return
	}
	username := session.Values["username"].(string)

	var args map[string]interface{}

	if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	filePath := args["path"].(string)
	curDir := filePath[:strings.LastIndex(filePath, conf.PathSeparator)]
	filename := filePath[strings.LastIndex(filePath, conf.PathSeparator)+1:]

	fout, err := os.Create(filePath)

	if nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	code := args["code"].(string)
	fout.WriteString(code)

	if err := fout.Close(); nil != err {
		logger.Error(err)
		data["succ"] = false

		return
	}

	line := int(args["cursorLine"].(float64))
	ch := int(args["cursorCh"].(float64))

	offset := getCursorOffset(code, line, ch)
	logger.Tracef("offset [%d]", offset)

	ideStub := util.Go.GetExecutableInGOBIN("ide_stub")
	argv := []string{"type", "-cursor", filename + ":" + strconv.Itoa(offset), "-use", "."}
	cmd := exec.Command(ideStub, argv...)
	cmd.Dir = curDir

	setCmdEnv(cmd, username)

	output, err := cmd.CombinedOutput()
	if nil != err {
		logger.Error(err)
		http.Error(w, err.Error(), 500)

		return
	}

	result := strings.TrimSpace(string(output))
	if "" == result {
		data["succ"] = false

		return
	}

	founds := strings.Split(result, "\n")
	usages := []*file.Snippet{}
	for _, found := range founds {
		found = strings.TrimSpace(found)

		part := found[:strings.LastIndex(found, ":")]
		cursorSep := strings.LastIndex(part, ":")
		path := found[:cursorSep]
		cursorLine, _ := strconv.Atoi(found[cursorSep+1 : strings.LastIndex(found, ":")])
		cursorCh, _ := strconv.Atoi(found[strings.LastIndex(found, ":")+1:])

		usage := &file.Snippet{Path: path, Line: cursorLine, Ch: cursorCh, Contents: []string{""}}
		usages = append(usages, usage)
	}

	data["founds"] = usages
}

// getCursorOffset calculates the cursor offset.
//
// line is the line number, starts with 0 that means the first line
// ch is the column number, starts with 0 that means the first column
func getCursorOffset(code string, line, ch int) (offset int) {
	lines := strings.Split(code, "\n")

	// calculate sum length of lines before
	for i := 0; i < line; i++ {
		offset += len(lines[i])
	}

	// calculate length of the current line and column
	curLine := lines[line]
	var buffer bytes.Buffer
	r := []rune(curLine)
	for i := 0; i < ch; i++ {
		buffer.WriteString(string(r[i]))
	}

	offset += len(buffer.String()) // append length of current line
	offset += line                 // append number of '\n'

	return offset
}

func setCmdEnv(cmd *exec.Cmd, username string) {
	userWorkspace := conf.GetUserWorkspace(username)

	cmd.Env = append(cmd.Env,
		"GOPATH="+userWorkspace,
		"GOOS="+runtime.GOOS,
		"GOARCH="+runtime.GOARCH,
		"GOROOT="+runtime.GOROOT(),
		"PATH="+os.Getenv("PATH"))
}
<|endoftext|>


<commit_before>package koding

import (
	"encoding/json"
	"fmt"
	"koding/db/models"
	"koding/kites/kloud/protocol"
	"net/http"
	"net/url"
	"time"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

type SubscriptionsResponse struct {
	AccountId          string    `json:"accountId"`
	PlanTitle          string    `json:"planTitle"`
	PlanInterval       string    `json:"planInterval"`
	State              string    `json:"state"`
	CurrentPeriodStart time.Time `json:"currentPeriodStart"`
	CurrentPeriodEnd   time.Time `json:"currentPeriodEnd"`
	Description        string    `json:"description"`
	Error              string    `json:"error"`
}

type FetcherResponse struct {
	Plan  Plan
	State string
}

func (p *Provider) Fetcher(m *protocol.Machine) (fetcherResp *FetcherResponse, planErr error) {
	defer func() {
		if planErr != nil {
			p.Log.Warning("[%s] username: %s could not fetch plan. Fallback to Free plan. err: '%s'",
				m.Id, m.Username, planErr)

			fetcherResp = &FetcherResponse{Plan: Free}
			planErr = nil
		}
	}()

	userEndpoint, err := url.Parse(p.PaymentEndpoint)
	if err != nil {
		return nil, err
	}

	var account *models.Account
	if err := p.Session.Run("jAccounts", func(c *mgo.Collection) error {
		return c.Find(bson.M{"profile.nickname": m.Username}).One(&account)
	}); err != nil {
		return nil, err
	}

	q := userEndpoint.Query()
	q.Set("account_id", account.Id.Hex())
	userEndpoint.RawQuery = q.Encode()

	p.Log.Debug("[%s] fetching plan via URL: '%s'", m.Id, userEndpoint.String())
	resp, err := http.Get(userEndpoint.String())
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var subscription *SubscriptionsResponse
	e := json.NewDecoder(resp.Body)
	if err := e.Decode(&subscription); err != nil {
		return nil, err
	}

	// return an error back for a non 200 status
	if resp.StatusCode != 200 {
		if subscription.Error != "" {
			return nil, fmt.Errorf("[%s] could not fetch subscription. err: '%s'",
				m.Id, subscription.Description)
		}

		return nil, fmt.Errorf("[%s] could not fetch subscription. status code: %d",
			m.Id, resp.StatusCode)
	}

	plan, ok := plans[subscription.PlanTitle]
	if !ok {
		return nil, fmt.Errorf("[%s] could not find plan. There is no plan called '%s'",
			m.Id, subscription.PlanTitle)
	}

	p.Log.Debug("[%s] user has plan: %s", m.Id, plan)
	return &FetcherResponse{
		Plan:  plan,
		State: subscription.State,
	}, nil
}
<commit_msg>kloud: remove annoying debug log<commit_after>package koding

import (
	"encoding/json"
	"fmt"
	"koding/db/models"
	"koding/kites/kloud/protocol"
	"net/http"
	"net/url"
	"time"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

type SubscriptionsResponse struct {
	AccountId          string    `json:"accountId"`
	PlanTitle          string    `json:"planTitle"`
	PlanInterval       string    `json:"planInterval"`
	State              string    `json:"state"`
	CurrentPeriodStart time.Time `json:"currentPeriodStart"`
	CurrentPeriodEnd   time.Time `json:"currentPeriodEnd"`
	Description        string    `json:"description"`
	Error              string    `json:"error"`
}

type FetcherResponse struct {
	Plan  Plan
	State string
}

func (p *Provider) Fetcher(m *protocol.Machine) (fetcherResp *FetcherResponse, planErr error) {
	defer func() {
		if planErr != nil {
			p.Log.Warning("[%s] username: %s could not fetch plan. Fallback to Free plan. err: '%s'",
				m.Id, m.Username, planErr)

			fetcherResp = &FetcherResponse{Plan: Free}
			planErr = nil
		}
	}()

	userEndpoint, err := url.Parse(p.PaymentEndpoint)
	if err != nil {
		return nil, err
	}

	var account *models.Account
	if err := p.Session.Run("jAccounts", func(c *mgo.Collection) error {
		return c.Find(bson.M{"profile.nickname": m.Username}).One(&account)
	}); err != nil {
		return nil, err
	}

	q := userEndpoint.Query()
	q.Set("account_id", account.Id.Hex())
	userEndpoint.RawQuery = q.Encode()

	p.Log.Debug("[%s] fetching plan via URL: '%s'", m.Id, userEndpoint.String())
	resp, err := http.Get(userEndpoint.String())
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var subscription *SubscriptionsResponse
	e := json.NewDecoder(resp.Body)
	if err := e.Decode(&subscription); err != nil {
		return nil, err
	}

	// return an error back for a non 200 status
	if resp.StatusCode != 200 {
		if subscription.Error != "" {
			return nil, fmt.Errorf("[%s] could not fetch subscription. err: '%s'",
				m.Id, subscription.Description)
		}

		return nil, fmt.Errorf("[%s] could not fetch subscription. status code: %d",
			m.Id, resp.StatusCode)
	}

	plan, ok := plans[subscription.PlanTitle]
	if !ok {
		return nil, fmt.Errorf("[%s] could not find plan. There is no plan called '%s'",
			m.Id, subscription.PlanTitle)
	}

	return &FetcherResponse{
		Plan:  plan,
		State: subscription.State,
	}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"koding/common"
	"koding/workers/tunnelproxymanager"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/koding/logging"
)

const Name = "tunnelproxymanager"

func main() {
	conf, awsconfig, err := tunnelproxymanager.Configure()
	if err != nil {
		log.Fatal("Reading config failed: ", err.Error())
	}

	// system name defines all resource names
	systemName := fmt.Sprintf("%s-%s", "tunnelproxymanager", conf.EBEnvName)

	log := common.CreateLogger(Name, conf.Debug)
	// remove formatting from call stack and output correct line
	log.SetCallDepth(1)

	// create record manager
	recordManager := tunnelproxymanager.NewRecordManager(awsconfig, log, conf.Region, conf.HostedZone)
	if err := recordManager.Init(); err != nil {
		log.Fatal(err.Error())
	}

	// create lifecycle
	l := tunnelproxymanager.NewLifeCycle(awsconfig, log, conf.AutoScalingName)

	// configure lifecycle with system name
	if err := l.Configure(systemName); err != nil {
		log.Fatal(err.Error())
	}

	done := registerSignalHandler(l, log)

	// listen to lifecycle events
	if err := l.Listen(recordManager); err != nil {
		log.Fatal(err.Error())
	}

	<-done
}

func registerSignalHandler(l *tunnelproxymanager.LifeCycle, log logging.Logger) chan struct{} {
	done := make(chan struct{}, 1)

	go func() {
		signals := make(chan os.Signal, 1)
		signal.Notify(signals)
		for {
			signal := <-signals
			switch signal {
			case syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGSTOP, syscall.SIGKILL:
				log.Info("recieved exit signal, closing...")
				err := l.Close()
				if err != nil {
					log.Critical(err.Error())
				}
				close(done)
			}
		}
	}()
	return done
}
<commit_msg>Tunnelproxymanager: remove for loop<commit_after>package main

import (
	"fmt"
	"koding/common"
	"koding/workers/tunnelproxymanager"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/koding/logging"
)

const Name = "tunnelproxymanager"

func main() {
	conf, awsconfig, err := tunnelproxymanager.Configure()
	if err != nil {
		log.Fatal("Reading config failed: ", err.Error())
	}

	// system name defines all resource names
	systemName := fmt.Sprintf("%s-%s", "tunnelproxymanager", conf.EBEnvName)

	log := common.CreateLogger(Name, conf.Debug)
	// remove formatting from call stack and output correct line
	log.SetCallDepth(1)

	// create record manager
	recordManager := tunnelproxymanager.NewRecordManager(awsconfig, log, conf.Region, conf.HostedZone)
	if err := recordManager.Init(); err != nil {
		log.Fatal(err.Error())
	}

	// create lifecycle
	l := tunnelproxymanager.NewLifeCycle(awsconfig, log, conf.AutoScalingName)

	// configure lifecycle with system name
	if err := l.Configure(systemName); err != nil {
		log.Fatal(err.Error())
	}

	done := registerSignalHandler(l, log)

	// listen to lifecycle events
	if err := l.Listen(recordManager); err != nil {
		log.Fatal(err.Error())
	}

	<-done
}

func registerSignalHandler(l *tunnelproxymanager.LifeCycle, log logging.Logger) chan struct{} {
	done := make(chan struct{}, 1)

	go func() {
		signals := make(chan os.Signal, 1)
		signal.Notify(signals)

		signal := <-signals
		switch signal {
		case syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGSTOP, syscall.SIGKILL:
			log.Info("recieved exit signal, closing...")
			err := l.Close()
			if err != nil {
				log.Critical(err.Error())
			}
			close(done)
		}

	}()
	return done
}
<|endoftext|>


<commit_before>package gorma

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}app.{{gotypename . 0}} storage type{{end}}
// Identifier: {{ $typeName :=  gotypename . 0}}{{$typeName := demodel $typeName}}
{{$td := gotypedef . 0 true false}}type {{$typeName}} {{modeldef $td .}}
{{ $belongsto := index .Metadata "github.com/bketelsen/gorma#belongsto" }}
{{ $m2m := index .Metadata "github.com/bketelsen/gorma#many2many" }}
func {{$typeName}}FromCreatePayload(ctx *app.Create{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	{{ if ne $belongsto "" }} m.{{ $belongsto }}ID=int(ctx.{{ demodel $belongsto }}ID){{end}}
	return m
}

func {{$typeName}}FromUpdatePayload(ctx *app.Update{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}
func (m {{$typeName}}) ToApp() *app.{{demodel $typeName}} {
	target := app.{{demodel $typeName}}{}
	copier.Copy(&target, &m)
	return &target
}
{{ $roler := index .Metadata "github.com/bketelsen/gorma#roler" }}
{{ if ne $roler "" }}
func (m {{$typeName}}) GetRole() string {
	return m.Role
}
{{end}}

type {{$typeName}}Storage interface {
	List(ctx goa.Context) []{{$typeName}}
	Get(ctx goa.Context, id int) ({{$typeName}}, error)
	Add(ctx goa.Context, o {{$typeName}}) ({{$typeName}}, error)
	Update(ctx goa.Context, o {{$typeName}}) (error)
	Delete(ctx goa.Context, id int) (error)
	{{ storagedef . }}
}

type {{$typeName}}DB struct {
	DB gorm.DB
}
/*{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
// would prefer to just pass a context in here, but they're all different, so can't
func {{$typeName}}Filter(parentid int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {
	if parentid > 0 {
		return func(db *gorm.DB) *gorm.DB {
			return db.Where("{{ snake $bt }}_id = ?", parentid)
		}
	} else {
		return func(db *gorm.DB) *gorm.DB {
			return db
		}
	}
}{{end}}{{end}}
*/
func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	return &{{$typeName}}DB{DB: db}
}

func (m *{{$typeName}}DB) List(ctx goa.Context) []{{$typeName}} {

	var objs []{{$typeName}}
    m.DB.Find(&objs)
	return objs
}

func (m *{{$typeName}}DB) Get(ctx goa.Context, id int) ({{$typeName}}, error) {

	var obj {{$typeName}}

	err := m.DB.Find(&obj, id).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx goa.Context, model {{$typeName}}) ({{$typeName}}, error) {
	err := m.DB.Create(&model).Error
	return model, err
}
func (m *{{$typeName}}DB) Update(ctx goa.Context, model {{$typeName}}) error {
	obj, err := m.Get(ctx, model.ID)
	if err != nil {
		return  err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return err
}
func (m *{{$typeName}}DB) Delete(ctx goa.Context, id int)  error {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}

{{ if ne $m2m "" }}{{$barray := split $m2m ","}}{{ range $idx, $bt := $barray}}
{{ $pieces := split $bt ":" }} {{ $lowertype := index $pieces 1  }} {{ $lower := lower $lowertype }}  {{ $lowerplural := index $pieces 0  }} {{ $lowerplural := lower $lowerplural}}
func (m *{{$typeName}}DB) Delete{{index $pieces 1}}(ctx goa.Context, {{$lower}}ID int)  error {
	var obj {{$typeName}}

	var assoc {{index $pieces 1}}
	var err error
	assoc.ID = {{$lower}}ID
	if err != nil {
		return err
	}
	err = m.DB.Model(&obj).Association("{{index $pieces 0}}").Delete(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) Add{{index $pieces 1}}(ctx goa.Context, {{lower $typeName}}ID, {{$lower}}ID int) error {
	var assoc {{index $pieces 1}}
	assoc.ID = {{$lower}}ID
	err := m.DB.Model(&{{$lower}}).Association("{{index $pieces 0}}").Append(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) List{{index $pieces 0}}(ctx goa.Context, {{lower $typeName}}ID int)  []{{index $pieces 1}} {
	list := make([]{{index $pieces 1}}, 0)
	var obj {{$typeName}}
	obj.ID = {{lower $typeName}}ID
	err := m.DB.Model(&obj).Association("{{index $pieces 0}}").Find(&list).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  list
	}
	return  nil
}
{{end}}{{end}}
{{if ne $belongsto ""}}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
func Filter{{$typeName}}By{{$bt}}(parent int, list []{{$typeName}}) []{{$typeName}} {
	filtered := make([]{{$typeName}},0)
	for _,o := range list {
		if o.{{$bt}}ID == int(parent) {
			filtered = append(filtered,o)
		}
	}
	return filtered
}
{{end}}{{end}}
`
<commit_msg>decouple contexts<commit_after>package gorma

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}app.{{gotypename . 0}} storage type{{end}}
// Identifier: {{ $typeName :=  gotypename . 0}}{{$typeName := demodel $typeName}}
{{$td := gotypedef . 0 true false}}type {{$typeName}} {{modeldef $td .}}
{{ $belongsto := index .Metadata "github.com/bketelsen/gorma#belongsto" }}
{{ $m2m := index .Metadata "github.com/bketelsen/gorma#many2many" }}
func {{$typeName}}FromCreatePayload(ctx *app.Create{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	{{ if ne $belongsto "" }} m.{{ $belongsto }}ID=int(ctx.{{ demodel $belongsto }}ID){{end}}
	return m
}

func {{$typeName}}FromUpdatePayload(ctx *app.Update{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}
func (m {{$typeName}}) ToApp() *app.{{demodel $typeName}} {
	target := app.{{demodel $typeName}}{}
	copier.Copy(&target, &m)
	return &target
}
{{ $roler := index .Metadata "github.com/bketelsen/gorma#roler" }}
{{ if ne $roler "" }}
func (m {{$typeName}}) GetRole() string {
	return m.Role
}
{{end}}

type {{$typeName}}Storage interface {
	List(ctx goa.Context) []{{$typeName}}
	Get(ctx goa.Context, id int) ({{$typeName}}, error)
	Add(ctx goa.Context, o {{$typeName}}) ({{$typeName}}, error)
	Update(ctx goa.Context, o {{$typeName}}) (error)
	Delete(ctx goa.Context, id int) (error)
	{{ storagedef . }}
}

type {{$typeName}}DB struct {
	DB gorm.DB
}
/*{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
// would prefer to just pass a context in here, but they're all different, so can't
func {{$typeName}}Filter(parentid int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {
	if parentid > 0 {
		return func(db *gorm.DB) *gorm.DB {
			return db.Where("{{ snake $bt }}_id = ?", parentid)
		}
	} else {
		return func(db *gorm.DB) *gorm.DB {
			return db
		}
	}
}{{end}}{{end}}
*/
func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	return &{{$typeName}}DB{DB: db}
}

func (m *{{$typeName}}DB) List(ctx goa.Context) []{{$typeName}} {

	var objs []{{$typeName}}
    m.DB.Find(&objs)
	return objs
}

func (m *{{$typeName}}DB) Get(ctx goa.Context, id int) ({{$typeName}}, error) {

	var obj {{$typeName}}

	err := m.DB.Find(&obj, id).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx goa.Context, model {{$typeName}}) ({{$typeName}}, error) {
	err := m.DB.Create(&model).Error
	return model, err
}
func (m *{{$typeName}}DB) Update(ctx goa.Context, model {{$typeName}}) error {
	obj, err := m.Get(ctx, model.ID)
	if err != nil {
		return  err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return err
}
func (m *{{$typeName}}DB) Delete(ctx goa.Context, id int)  error {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}

{{ if ne $m2m "" }}{{$barray := split $m2m ","}}{{ range $idx, $bt := $barray}}
{{ $pieces := split $bt ":" }} {{ $lowertype := index $pieces 1  }} {{ $lower := lower $lowertype }}  {{ $lowerplural := index $pieces 0  }} {{ $lowerplural := lower $lowerplural}}
func (m *{{$typeName}}DB) Delete{{index $pieces 1}}(ctx goa.Context, {{$lower}}ID int)  error {
	var obj {{$typeName}}

	var assoc {{index $pieces 1}}
	var err error
	assoc.ID = {{$lower}}ID
	if err != nil {
		return err
	}
	err = m.DB.Model(&obj).Association("{{index $pieces 0}}").Delete(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) Add{{index $pieces 1}}(ctx goa.Context, {{lower $typeName}}ID, {{$lower}}ID int) error {
	var {{lower $typeName}} {{$typeName}}
	{{lower $typeName}}.ID = {{lower $typeName}}ID
	var assoc {{index $pieces 1}}
	assoc.ID = {{$lower}}ID
	err := m.DB.Model(&{{lower $typeName}}).Association("{{index $pieces 0}}").Append(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) List{{index $pieces 0}}(ctx goa.Context, {{lower $typeName}}ID int)  []{{index $pieces 1}} {
	list := make([]{{index $pieces 1}}, 0)
	var obj {{$typeName}}
	obj.ID = {{lower $typeName}}ID
	err := m.DB.Model(&obj).Association("{{index $pieces 0}}").Find(&list).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  list
	}
	return  nil
}
{{end}}{{end}}
{{if ne $belongsto ""}}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
func Filter{{$typeName}}By{{$bt}}(parent int, list []{{$typeName}}) []{{$typeName}} {
	filtered := make([]{{$typeName}},0)
	for _,o := range list {
		if o.{{$bt}}ID == int(parent) {
			filtered = append(filtered,o)
		}
	}
	return filtered
}
{{end}}{{end}}
`
<|endoftext|>