<commit_before>package discordgo

import (
	"testing"
)

//////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////// START OF TESTS

// TestChannelMessageSend tests the ChannelMessageSend() function. This should not return an error.
func TestChannelMessageSend(t *testing.T) {

	if envChannel == "" {
		t.Skip("Skipping, DG_CHANNEL not set.")
	}

	if dg == nil {
		t.Skip("Skipping, dg not set.")
	}

	_, err := dg.ChannelMessageSend(envChannel, "Running REST API Tests!")
	if err != nil {
		t.Errorf("ChannelMessageSend returned error: %+v", err)
	}
}

func TestUserAvatar(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot TestUserAvatar, dg not set.")
	}

	a, err := dg.UserAvatar("@me")
	if err != nil {
		if err.Error() == `HTTP 404 NOT FOUND, {"message": ""}` {
			t.Skip("Skipped, @me doesn't have an Avatar")
		}
		t.Errorf(err.Error())
	}

	if a == nil {
		t.Errorf("a == nil, should be image.Image")
	}
}

/* Running this causes an error due to 2/hour rate limit on username changes
func TestUserUpdate(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot test logout, dg not set.")
	}

	u, err := dg.User("@me")
	if err != nil {
		t.Errorf(err.Error())
	}

	s, err := dg.UserUpdate(envEmail, envPassword, "testname", u.Avatar, "")
	if err != nil {
		t.Error(err.Error())
	}
	if s.Username != "testname" {
		t.Error("Username != testname")
	}
	s, err = dg.UserUpdate(envEmail, envPassword, u.Username, u.Avatar, "")
	if err != nil {
		t.Error(err.Error())
	}
	if s.Username != u.Username {
		t.Error("Username != " + u.Username)
	}
}
*/

//func (s *Session) UserChannelCreate(recipientID string) (st *Channel, err error) {

func TestUserChannelCreate(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot TestUserChannelCreate, dg not set.")
	}

	if envAdmin == "" {
		t.Skip("Skipped, DG_ADMIN not set.")
	}

	_, err := dg.UserChannelCreate(envAdmin)
	if err != nil {
		t.Errorf(err.Error())
	}

	// TODO make sure the channel was added
}

func TestUserChannels(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot TestUserChannels, dg not set.")
	}

	_, err := dg.UserChannels()
	if err != nil {
		t.Errorf(err.Error())
	}
}

func TestUserGuilds(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot TestUserGuilds, dg not set.")
	}

	_, err := dg.UserGuilds()
	if err != nil {
		t.Errorf(err.Error())
	}
}

func TestUserSettings(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot TestUserSettings, dg not set.")
	}

	_, err := dg.UserSettings()
	if err != nil {
		t.Errorf(err.Error())
	}
}

// TestLogout tests the Logout() function. This should not return an error.
func TestLogout(t *testing.T) {

	if dg == nil {
		t.Skip("Cannot TestLogout, dg not set.")
	}

	err := dg.Logout()
	if err != nil {
		t.Errorf("Logout() returned error: %+v", err)
	}
}

func TestGateway(t *testing.T) {

	_, err := dg.Gateway()
	if err != nil {
		t.Errorf("Gateway() returned error: %+v", err)
	}
}

func TestVoiceICE(t *testing.T) {

	if dg == nil {
		t.Skip("Skipping, dg not set.")
	}

	_, err := dg.VoiceICE()
	if err != nil {
		t.Errorf("VoiceICE() returned error: %+v", err)
	}
}

func TestVoiceRegions(t *testing.T) {

	if dg == nil {
		t.Skip("Skipping, dg not set.")
	}

	_, err := dg.VoiceRegions()
	if err != nil {
		t.Errorf("VoiceRegions() returned error: %+v", err)
	}
}
func TestGuildRoles(t *testing.T) {

	if envGuild == "" {
		t.Skip("Skipping, DG_GUILD not set.")
	}

	if dg == nil {
		t.Skip("Skipping, dg not set.")
	}

	_, err := dg.GuildRoles(envGuild)
	if err != nil {
		t.Errorf("GuildRoles(envGuild) returned error: %+v", err)
	}

}

// TestChannelMessageSend2 tests the ChannelMessageSend() function. This should not return an error.
func TestChannelMessageSend2(t *testing.T) {

	if envChannel == "" {
		t.Skip("Skipping, DG_CHANNEL not set.")
	}

	if dg == nil {
		t.Skip("Skipping, dg not set.")
	}

	_, err := dg.ChannelMessageSend(envChannel, "All done running REST API Tests!")
	if err != nil {
		t.Errorf("ChannelMessageSend returned error: %+v", err)
	}
}
<commit_msg>dg nil check on TestGateway<commit_after>package discordgo

import (
	"testing"
)

//////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////// START OF TESTS

// TestChannelMessageSend tests the ChannelMessageSend() function. This should not return an error.
func TestChannelMessageSend(t *testing.T) {

	if envChannel == "" {
		t.Skip("Skipping, DG_CHANNEL not set.")
	}

	if dg == nil {
		t.Skip("Skipping, dg not set.")
	}

	_, err := dg.ChannelMessageSend(envChannel, "Running REST API Tests!")
	if err != nil {
		t.Errorf("ChannelMessageSend returned error: %+v", err)
	}
}

func TestUserAvatar(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot TestUserAvatar, dg not set.")
	}

	a, err := dg.UserAvatar("@me")
	if err != nil {
		if err.Error() == `HTTP 404 NOT FOUND, {"message": ""}` {
			t.Skip("Skipped, @me doesn't have an Avatar")
		}
		t.Errorf(err.Error())
	}

	if a == nil {
		t.Errorf("a == nil, should be image.Image")
	}
}

/* Running this causes an error due to 2/hour rate limit on username changes
func TestUserUpdate(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot test logout, dg not set.")
	}

	u, err := dg.User("@me")
	if err != nil {
		t.Errorf(err.Error())
	}

	s, err := dg.UserUpdate(envEmail, envPassword, "testname", u.Avatar, "")
	if err != nil {
		t.Error(err.Error())
	}
	if s.Username != "testname" {
		t.Error("Username != testname")
	}
	s, err = dg.UserUpdate(envEmail, envPassword, u.Username, u.Avatar, "")
	if err != nil {
		t.Error(err.Error())
	}
	if s.Username != u.Username {
		t.Error("Username != " + u.Username)
	}
}
*/

//func (s *Session) UserChannelCreate(recipientID string) (st *Channel, err error) {

func TestUserChannelCreate(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot TestUserChannelCreate, dg not set.")
	}

	if envAdmin == "" {
		t.Skip("Skipped, DG_ADMIN not set.")
	}

	_, err := dg.UserChannelCreate(envAdmin)
	if err != nil {
		t.Errorf(err.Error())
	}

	// TODO make sure the channel was added
}

func TestUserChannels(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot TestUserChannels, dg not set.")
	}

	_, err := dg.UserChannels()
	if err != nil {
		t.Errorf(err.Error())
	}
}

func TestUserGuilds(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot TestUserGuilds, dg not set.")
	}

	_, err := dg.UserGuilds()
	if err != nil {
		t.Errorf(err.Error())
	}
}

func TestUserSettings(t *testing.T) {
	if dg == nil {
		t.Skip("Cannot TestUserSettings, dg not set.")
	}

	_, err := dg.UserSettings()
	if err != nil {
		t.Errorf(err.Error())
	}
}

// TestLogout tests the Logout() function. This should not return an error.
func TestLogout(t *testing.T) {

	if dg == nil {
		t.Skip("Cannot TestLogout, dg not set.")
	}

	err := dg.Logout()
	if err != nil {
		t.Errorf("Logout() returned error: %+v", err)
	}
}

func TestGateway(t *testing.T) {

	if dg == nil {
		t.Skip("Skipping, dg not set.")
	}
	_, err := dg.Gateway()
	if err != nil {
		t.Errorf("Gateway() returned error: %+v", err)
	}
}

func TestVoiceICE(t *testing.T) {

	if dg == nil {
		t.Skip("Skipping, dg not set.")
	}

	_, err := dg.VoiceICE()
	if err != nil {
		t.Errorf("VoiceICE() returned error: %+v", err)
	}
}

func TestVoiceRegions(t *testing.T) {

	if dg == nil {
		t.Skip("Skipping, dg not set.")
	}

	_, err := dg.VoiceRegions()
	if err != nil {
		t.Errorf("VoiceRegions() returned error: %+v", err)
	}
}
func TestGuildRoles(t *testing.T) {

	if envGuild == "" {
		t.Skip("Skipping, DG_GUILD not set.")
	}

	if dg == nil {
		t.Skip("Skipping, dg not set.")
	}

	_, err := dg.GuildRoles(envGuild)
	if err != nil {
		t.Errorf("GuildRoles(envGuild) returned error: %+v", err)
	}

}

// TestChannelMessageSend2 tests the ChannelMessageSend() function. This should not return an error.
func TestChannelMessageSend2(t *testing.T) {

	if envChannel == "" {
		t.Skip("Skipping, DG_CHANNEL not set.")
	}

	if dg == nil {
		t.Skip("Skipping, dg not set.")
	}

	_, err := dg.ChannelMessageSend(envChannel, "All done running REST API Tests!")
	if err != nil {
		t.Errorf("ChannelMessageSend returned error: %+v", err)
	}
}
<|endoftext|>


<commit_before>package flagparse

import (
	"fmt"
	"os"
	"path"
)

// ArgumentParser is a struct for parsing command line strings
type ArgumentParser struct {
	prog string
}

// NewArgumentParser returns new ArgumentParser pointer
func NewArgumentParser(prog string) *ArgumentParser {
	ap := &ArgumentParser{}
	if prog == "" {
		prog = path.Base(os.Args[0])
	}
	ap.prog = prog
	return ap
}

func (ap *ArgumentParser) ParseArgs(args, namespace string) {
	fmt.Printf("usage: %s [-h]\n", ap.prog)
	fmt.Println(`
optional arguments:
  -h, --help  show this help message and exit`)
}
<commit_msg>Print error message when receive unrecogonized arguments.<commit_after>package flagparse

import (
	"fmt"
	"os"
	"path"
)

// ArgumentParser is a struct for parsing command line strings
type ArgumentParser struct {
	prog string
}

// NewArgumentParser returns new ArgumentParser pointer
func NewArgumentParser(prog string) *ArgumentParser {
	ap := &ArgumentParser{}
	if prog == "" {
		prog = path.Base(os.Args[0])
	}
	ap.prog = prog
	return ap
}

func (ap *ArgumentParser) ParseArgs(args, namespace string) {
	var argList []string
	if args == "" {
		argList = os.Args[1:]
	}
	fmt.Printf("usage: %s [-h]\n", ap.prog)

	if 0 < len(argList) && (argList[0] == "-h" || argList[0] == "--help") {
		fmt.Println(`
optional arguments:
  -h, --help  show this help message and exit`)
	} else {
		fmt.Printf("%s: error: unrecognized arguments %s\n", ap.prog, argList[0])
	}
}
<|endoftext|>


<commit_before>// bridge bridges between IRC clients (RFC1459) and RobustIRC servers.
//
// Bridge instances are supposed to be long-running, and ideally as close to the
// IRC client as possible, e.g. on the same machine. When running on the same
// machine, there should not be any network problems between the IRC client and
// the bridge. Network problems between the bridge and a RobustIRC network are
// handled transparently.
package main

import (
	"bufio"
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net"
	"os"
	"strings"
	"time"

	"github.com/robustirc/bridge/robustsession"

	"github.com/sorcix/irc"
)

var (
	network = flag.String("network",
		"",
		`DNS name to connect to (e.g. "robustirc.net"). The _robustirc._tcp SRV record must be present.`)

	listen = flag.String("listen",
		"localhost:6667",
		"host:port to listen on for IRC connections")

	socks = flag.String("socks",
		"localhost:1080",
		"host:port to listen on for SOCKS5 connections")

	tlsCertPath = flag.String("tls_cert_path",
		"",
		"Path to a .pem file containing the TLS certificate. If unspecified, TLS is not used.")

	tlsKeyPath = flag.String("tls_key_path",
		"",
		"Path to a .pem file containing the TLS private key. If unspecified, TLS is not used.")

	tlsCAFile = flag.String("tls_ca_file",
		"",
		"Use the specified file as trusted CA instead of the system CAs. Useful for testing.")

	motdPath = flag.String("motd_path",
		"/usr/share/robustirc/bridge-motd.txt",
		"Path to a text file containing the message of the day (MOTD) to prefix to the network MOTD.")
)

// TODO(secure): persistent state:
// - the last known server(s) in the network. added to *servers
// - for resuming sessions (later): the last seen message id, perhaps setup messages (JOINs, MODEs, …)
// for hosted mode, this state is stored per-nickname, ideally encrypted with password

// prefixMotd takes an irc.MOTD message from the server and prefixes it with
// our own MOTD. E.g., it takes:
//   :robustirc.net 372 sECuRE :- First line of MOTD\r\n
// and turns that into:
//   :robustirc.net 372 sECuRE :- First line of bridge MOTD\r\n
//   :robustirc.net 372 sECuRE :- Thanks for using this bridge! Enjoy!\r\n
//   :robustirc.net 372 sECuRE :- First line of MOTD\r\n
func prefixMotd(msg string) string {
	// The user chose to not inject a MOTD.
	if *motdPath == "" {
		return msg
	}

	sep := strings.Index(msg[1:], ":")
	if sep == -1 {
		return msg
	}

	prefix := msg[:sep+2] + "- "

	f, err := os.Open(*motdPath)
	if err != nil {
		log.Printf("Cannot inject MOTD: %v\n", err)
		return msg
	}
	defer f.Close()

	var injected []string

	reader := bufio.NewReader(f)
	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Printf("Cannot inject MOTD: %v\n", err)
			return msg
		}
		if len(line) > 0 && line[len(line)-1] == '\r' {
			line = line[:len(line)-1]
		}
		injected = append(injected, prefix+line)
	}

	return strings.Join(injected, "\r\n") + "\r\n" + msg
}

type bridge struct {
	network string
}

func newBridge(network string) *bridge {
	return &bridge{
		network: network,
	}
}

type ircsession struct {
	Messages chan irc.Message
	Errors   chan error

	conn    *irc.Conn
	rawConn net.Conn
}

func newIrcsession(conn net.Conn) *ircsession {
	s := &ircsession{
		Messages: make(chan irc.Message),
		Errors:   make(chan error),
		conn:     irc.NewConn(conn),
		rawConn:  conn,
	}
	go s.getMessages()
	return s
}

func (s *ircsession) Send(msg []byte) error {
	if _, err := s.conn.Write(msg); err != nil {
		return err
	}
	return nil
}

func (s *ircsession) Delete(killmsg string) error {
	defer s.conn.Close()
	// Read all remaining values to ensure nobody is blocked on sending.
	defer func() {
		go func() {
			for _ = range s.Messages {
			}
		}()
		go func() {
			for _ = range s.Errors {
			}
		}()
	}()

	if killmsg != "" {
		return s.conn.Encode(&irc.Message{
			Command:  "ERROR",
			Trailing: killmsg,
		})
	}

	return nil
}

func (s *ircsession) getMessages() {
	defer close(s.Messages)
	defer close(s.Errors)

	// Read the first byte. If it’s 4 or 5, this is likely SOCKS
	first := make([]byte, 1)
	if _, err := s.rawConn.Read(first); err != nil {
		s.Errors <- err
		return
	}

	// %x04 or %x05 as the first byte is both invalid according to RFC2812
	// section 2.3.1. Valid characters are ":" (%x3A) or %x30-39 (0-9) or
	// %x41-5A / %x61-7A (A-Z / a-z).
	// So we can just close the connection here, and also log that the user is
	// most likely trying to use SOCKS on the wrong port.
	//
	// TODO(secure): With some refactoring, we might even just handle the SOCKS
	// connection properly.
	if first[0] == 4 || first[0] == 5 {
		log.Printf("Read 0x%02x as first byte, which looks like a SOCKS version number. Please connect to %q instead of %q.\n", first[0], *socks, *listen)
		s.Errors <- fmt.Errorf("Read 0x%02x (SOCKS version?) as first byte on an IRC connection", first[0])
		return
	}

	line := []byte{first[0]}

	for first[0] != '\n' {
		if _, err := s.rawConn.Read(first); err != nil {
			s.Errors <- err
			return
		}
		line = append(line, first[0])
	}

	ircmsg := irc.ParseMessage(string(line))
	if ircmsg != nil {
		s.Messages <- *ircmsg
	}

	for {
		ircmsg, err := s.conn.Decode()
		if err != nil {
			s.Errors <- err
			return
		}
		// Skip invalid lines (to prevent nil pointer dereferences).
		if ircmsg == nil {
			continue
		}
		s.Messages <- *ircmsg
	}
}

func (p *bridge) handleIRC(conn net.Conn) {
	var quitmsg, killmsg string
	var waitingForPingReply bool

	ircSession := newIrcsession(conn)

	defer func() {
		log.Printf("Terminating IRC connection from %s. killmsg=%q\n", conn.RemoteAddr(), killmsg)
		if err := ircSession.Delete(killmsg); err != nil {
			log.Printf("Could not properly delete IRC session: %v\n", err)
		}
		// The separator makes it easier to read logs when the client is
		// reconnecting in a loop (which is the most common situation in which
		// you’re interested in the logs at all).
		log.Printf("\n")
	}()

	robustSession, err := robustsession.Create(p.network, *tlsCAFile)
	if err != nil {
		killmsg = fmt.Sprintf("Could not create RobustIRC session: %v", err)
		return
	}

	log.Printf("[session %s] Created RobustSession for client %s\n", robustSession.SessionId, conn.RemoteAddr())

	defer func() {
		log.Printf("[session %s] Deleting RobustSession. quitmsg=%q\n", robustSession.SessionId, quitmsg)
		if err := robustSession.Delete(quitmsg); err != nil {
			log.Printf("Could not properly delete RobustIRC session: %v\n", err)
		}
	}()

	var sendIRC, sendRobust []byte

	keepalivePong := ":" + robustSession.IrcPrefix.String() + " PONG keepalive"
	motdPrefix := ":" + robustSession.IrcPrefix.String() + " 372 "
	welcomePrefix := ":" + robustSession.IrcPrefix.String() + " 001 "
	welcomed := false
	motdInjected := false

	keepaliveToNetwork := time.After(1 * time.Minute)
	keepaliveToClient := time.After(1 * time.Minute)
	for {
		// These two variables contain the messages to be sent to IRC/RobustIRC
		// from the previous iteration of the state machine. That way, there is
		// only one place where the error handling happens.
		if sendIRC != nil {
			if err := ircSession.Send(sendIRC); err != nil {
				quitmsg = fmt.Sprintf("Bridge: Send to IRC client: %v", err)
				return
			}
			sendIRC = nil
		}
		if sendRobust != nil {
			if err := robustSession.PostMessage(string(sendRobust)); err != nil {
				killmsg = fmt.Sprintf("Could not post message to RobustIRC: %v", err)
				return
			}
			keepaliveToNetwork = time.After(1 * time.Minute)
			keepaliveToClient = time.After(1 * time.Minute)
			sendRobust = nil
		}

		select {
		case msg := <-robustSession.Messages:
			// Inject the bridge’s message of the day.
			if !motdInjected && strings.HasPrefix(msg, motdPrefix) {
				sendIRC = []byte(prefixMotd(msg))
				break
			}
			// For debugging purposes, print a log message when the client successfully logs into IRC.
			if !welcomed && strings.HasPrefix(msg, welcomePrefix) {
				log.Printf("[session %s] Successfully logged into IRC.\n", robustSession.SessionId)
				welcomed = true
			}
			if msg == keepalivePong {
				break
			}
			sendIRC = []byte(msg)

		case err := <-robustSession.Errors:
			killmsg = fmt.Sprintf("RobustIRC session error: %v", err)
			return

		case ircmsg := <-ircSession.Messages:
			switch strings.ToUpper(ircmsg.Command) {
			case irc.PONG:
				waitingForPingReply = false

			case irc.PING:
				sendIRC = (&irc.Message{
					Prefix:  robustSession.IrcPrefix,
					Command: irc.PONG,
					Params:  []string{ircmsg.Params[0]},
				}).Bytes()

			case irc.QUIT:
				quitmsg = ircmsg.Trailing
				return

			default:
				sendRobust = ircmsg.Bytes()
			}

		case err := <-ircSession.Errors:
			quitmsg = fmt.Sprintf("Bridge: Read from IRC client: %v", err)
			return

		case <-keepaliveToClient:
			// After no traffic in either direction for 1 minute, we send a PING
			// message. If a PING message was already sent, this means that we did
			// not receive a PONG message, so we close the connection with a
			// timeout.
			if waitingForPingReply {
				quitmsg = "Bridge: ping timeout"
				return
			}
			sendIRC = (&irc.Message{
				Prefix:  robustSession.IrcPrefix,
				Command: irc.PING,
				Params:  []string{"robustirc.bridge"},
			}).Bytes()
			waitingForPingReply = true

		case <-keepaliveToNetwork:
			sendRobust = []byte("PING keepalive")
			keepaliveToNetwork = time.After(1 * time.Minute)
		}
	}
}

// Copied from src/net/http/server.go
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}

// maybeTLSListener returns a net.Listener which possibly uses TLS, depending
// on the -tls_cert_path and -tls_key_path flag values.
func maybeTLSListener(addr string) net.Listener {
	if *tlsCertPath == "" || *tlsKeyPath == "" {
		ln, err := net.Listen("tcp", addr)
		if err != nil {
			log.Fatal(err)
		}
		return ln
	}

	tlsconfig := &tls.Config{
		Certificates: make([]tls.Certificate, 1),
	}

	var err error
	tlsconfig.Certificates[0], err = tls.LoadX509KeyPair(*tlsCertPath, *tlsKeyPath)
	if err != nil {
		log.Fatal(err)
	}

	ln, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(err)
	}

	return tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, tlsconfig)
}

func main() {
	flag.Parse()

	rand.Seed(time.Now().Unix())

	if (*network == "" && *socks == "") ||
		(*socks == "" && *listen == "") {
		log.Fatal("You must specify either -network and -listen, or -socks.")
	}

	// SOCKS and IRC
	if *socks != "" && *network != "" && *listen != "" {
		go func() {
			log.Printf("RobustIRC IRC bridge listening on %q (SOCKS)\n", *socks)
			if err := serveSocks(maybeTLSListener(*socks)); err != nil {
				log.Fatal(err)
			}
		}()
	}

	// SOCKS only
	if *socks != "" && (*network == "" || *listen == "") {
		log.Printf("RobustIRC IRC bridge listening on %q (SOCKS)\n", *socks)
		log.Fatal(serveSocks(maybeTLSListener(*socks)))
	}

	// IRC
	if *network != "" && *listen != "" {
		p := newBridge(*network)
		ln := maybeTLSListener(*listen)

		log.Printf("RobustIRC IRC bridge listening on %q (IRC)\n", *listen)

		for {
			conn, err := ln.Accept()
			if err != nil {
				log.Printf("Could not accept IRC client connection: %v\n", err)
				continue
			}
			go p.handleIRC(conn)
		}
	}
}
<commit_msg>Import crypto/sha* so that crypto/tls works on go1.0.2.<commit_after>// bridge bridges between IRC clients (RFC1459) and RobustIRC servers.
//
// Bridge instances are supposed to be long-running, and ideally as close to the
// IRC client as possible, e.g. on the same machine. When running on the same
// machine, there should not be any network problems between the IRC client and
// the bridge. Network problems between the bridge and a RobustIRC network are
// handled transparently.
package main

import (
	"bufio"
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net"
	"os"
	"strings"
	"time"

	"github.com/robustirc/bridge/robustsession"

	"github.com/sorcix/irc"

	// Necessary on go1.0.2 (debian wheezy) to make crypto/tls work with the
	// certificates on robustirc.net (and possibly others).
	_ "crypto/sha1"
	_ "crypto/sha256"
	_ "crypto/sha512"
)

var (
	network = flag.String("network",
		"",
		`DNS name to connect to (e.g. "robustirc.net"). The _robustirc._tcp SRV record must be present.`)

	listen = flag.String("listen",
		"localhost:6667",
		"host:port to listen on for IRC connections")

	socks = flag.String("socks",
		"localhost:1080",
		"host:port to listen on for SOCKS5 connections")

	tlsCertPath = flag.String("tls_cert_path",
		"",
		"Path to a .pem file containing the TLS certificate. If unspecified, TLS is not used.")

	tlsKeyPath = flag.String("tls_key_path",
		"",
		"Path to a .pem file containing the TLS private key. If unspecified, TLS is not used.")

	tlsCAFile = flag.String("tls_ca_file",
		"",
		"Use the specified file as trusted CA instead of the system CAs. Useful for testing.")

	motdPath = flag.String("motd_path",
		"/usr/share/robustirc/bridge-motd.txt",
		"Path to a text file containing the message of the day (MOTD) to prefix to the network MOTD.")
)

// TODO(secure): persistent state:
// - the last known server(s) in the network. added to *servers
// - for resuming sessions (later): the last seen message id, perhaps setup messages (JOINs, MODEs, …)
// for hosted mode, this state is stored per-nickname, ideally encrypted with password

// prefixMotd takes an irc.MOTD message from the server and prefixes it with
// our own MOTD. E.g., it takes:
//   :robustirc.net 372 sECuRE :- First line of MOTD\r\n
// and turns that into:
//   :robustirc.net 372 sECuRE :- First line of bridge MOTD\r\n
//   :robustirc.net 372 sECuRE :- Thanks for using this bridge! Enjoy!\r\n
//   :robustirc.net 372 sECuRE :- First line of MOTD\r\n
func prefixMotd(msg string) string {
	// The user chose to not inject a MOTD.
	if *motdPath == "" {
		return msg
	}

	sep := strings.Index(msg[1:], ":")
	if sep == -1 {
		return msg
	}

	prefix := msg[:sep+2] + "- "

	f, err := os.Open(*motdPath)
	if err != nil {
		log.Printf("Cannot inject MOTD: %v\n", err)
		return msg
	}
	defer f.Close()

	var injected []string

	reader := bufio.NewReader(f)
	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Printf("Cannot inject MOTD: %v\n", err)
			return msg
		}
		if len(line) > 0 && line[len(line)-1] == '\r' {
			line = line[:len(line)-1]
		}
		injected = append(injected, prefix+line)
	}

	return strings.Join(injected, "\r\n") + "\r\n" + msg
}

type bridge struct {
	network string
}

func newBridge(network string) *bridge {
	return &bridge{
		network: network,
	}
}

type ircsession struct {
	Messages chan irc.Message
	Errors   chan error

	conn    *irc.Conn
	rawConn net.Conn
}

func newIrcsession(conn net.Conn) *ircsession {
	s := &ircsession{
		Messages: make(chan irc.Message),
		Errors:   make(chan error),
		conn:     irc.NewConn(conn),
		rawConn:  conn,
	}
	go s.getMessages()
	return s
}

func (s *ircsession) Send(msg []byte) error {
	if _, err := s.conn.Write(msg); err != nil {
		return err
	}
	return nil
}

func (s *ircsession) Delete(killmsg string) error {
	defer s.conn.Close()
	// Read all remaining values to ensure nobody is blocked on sending.
	defer func() {
		go func() {
			for _ = range s.Messages {
			}
		}()
		go func() {
			for _ = range s.Errors {
			}
		}()
	}()

	if killmsg != "" {
		return s.conn.Encode(&irc.Message{
			Command:  "ERROR",
			Trailing: killmsg,
		})
	}

	return nil
}

func (s *ircsession) getMessages() {
	defer close(s.Messages)
	defer close(s.Errors)

	// Read the first byte. If it’s 4 or 5, this is likely SOCKS
	first := make([]byte, 1)
	if _, err := s.rawConn.Read(first); err != nil {
		s.Errors <- err
		return
	}

	// %x04 or %x05 as the first byte is both invalid according to RFC2812
	// section 2.3.1. Valid characters are ":" (%x3A) or %x30-39 (0-9) or
	// %x41-5A / %x61-7A (A-Z / a-z).
	// So we can just close the connection here, and also log that the user is
	// most likely trying to use SOCKS on the wrong port.
	//
	// TODO(secure): With some refactoring, we might even just handle the SOCKS
	// connection properly.
	if first[0] == 4 || first[0] == 5 {
		log.Printf("Read 0x%02x as first byte, which looks like a SOCKS version number. Please connect to %q instead of %q.\n", first[0], *socks, *listen)
		s.Errors <- fmt.Errorf("Read 0x%02x (SOCKS version?) as first byte on an IRC connection", first[0])
		return
	}

	line := []byte{first[0]}

	for first[0] != '\n' {
		if _, err := s.rawConn.Read(first); err != nil {
			s.Errors <- err
			return
		}
		line = append(line, first[0])
	}

	ircmsg := irc.ParseMessage(string(line))
	if ircmsg != nil {
		s.Messages <- *ircmsg
	}

	for {
		ircmsg, err := s.conn.Decode()
		if err != nil {
			s.Errors <- err
			return
		}
		// Skip invalid lines (to prevent nil pointer dereferences).
		if ircmsg == nil {
			continue
		}
		s.Messages <- *ircmsg
	}
}

func (p *bridge) handleIRC(conn net.Conn) {
	var quitmsg, killmsg string
	var waitingForPingReply bool

	ircSession := newIrcsession(conn)

	defer func() {
		log.Printf("Terminating IRC connection from %s. killmsg=%q\n", conn.RemoteAddr(), killmsg)
		if err := ircSession.Delete(killmsg); err != nil {
			log.Printf("Could not properly delete IRC session: %v\n", err)
		}
		// The separator makes it easier to read logs when the client is
		// reconnecting in a loop (which is the most common situation in which
		// you’re interested in the logs at all).
		log.Printf("\n")
	}()

	robustSession, err := robustsession.Create(p.network, *tlsCAFile)
	if err != nil {
		killmsg = fmt.Sprintf("Could not create RobustIRC session: %v", err)
		return
	}

	log.Printf("[session %s] Created RobustSession for client %s\n", robustSession.SessionId, conn.RemoteAddr())

	defer func() {
		log.Printf("[session %s] Deleting RobustSession. quitmsg=%q\n", robustSession.SessionId, quitmsg)
		if err := robustSession.Delete(quitmsg); err != nil {
			log.Printf("Could not properly delete RobustIRC session: %v\n", err)
		}
	}()

	var sendIRC, sendRobust []byte

	keepalivePong := ":" + robustSession.IrcPrefix.String() + " PONG keepalive"
	motdPrefix := ":" + robustSession.IrcPrefix.String() + " 372 "
	welcomePrefix := ":" + robustSession.IrcPrefix.String() + " 001 "
	welcomed := false
	motdInjected := false

	keepaliveToNetwork := time.After(1 * time.Minute)
	keepaliveToClient := time.After(1 * time.Minute)
	for {
		// These two variables contain the messages to be sent to IRC/RobustIRC
		// from the previous iteration of the state machine. That way, there is
		// only one place where the error handling happens.
		if sendIRC != nil {
			if err := ircSession.Send(sendIRC); err != nil {
				quitmsg = fmt.Sprintf("Bridge: Send to IRC client: %v", err)
				return
			}
			sendIRC = nil
		}
		if sendRobust != nil {
			if err := robustSession.PostMessage(string(sendRobust)); err != nil {
				killmsg = fmt.Sprintf("Could not post message to RobustIRC: %v", err)
				return
			}
			keepaliveToNetwork = time.After(1 * time.Minute)
			keepaliveToClient = time.After(1 * time.Minute)
			sendRobust = nil
		}

		select {
		case msg := <-robustSession.Messages:
			// Inject the bridge’s message of the day.
			if !motdInjected && strings.HasPrefix(msg, motdPrefix) {
				sendIRC = []byte(prefixMotd(msg))
				break
			}
			// For debugging purposes, print a log message when the client successfully logs into IRC.
			if !welcomed && strings.HasPrefix(msg, welcomePrefix) {
				log.Printf("[session %s] Successfully logged into IRC.\n", robustSession.SessionId)
				welcomed = true
			}
			if msg == keepalivePong {
				break
			}
			sendIRC = []byte(msg)

		case err := <-robustSession.Errors:
			killmsg = fmt.Sprintf("RobustIRC session error: %v", err)
			return

		case ircmsg := <-ircSession.Messages:
			switch strings.ToUpper(ircmsg.Command) {
			case irc.PONG:
				waitingForPingReply = false

			case irc.PING:
				sendIRC = (&irc.Message{
					Prefix:  robustSession.IrcPrefix,
					Command: irc.PONG,
					Params:  []string{ircmsg.Params[0]},
				}).Bytes()

			case irc.QUIT:
				quitmsg = ircmsg.Trailing
				return

			default:
				sendRobust = ircmsg.Bytes()
			}

		case err := <-ircSession.Errors:
			quitmsg = fmt.Sprintf("Bridge: Read from IRC client: %v", err)
			return

		case <-keepaliveToClient:
			// After no traffic in either direction for 1 minute, we send a PING
			// message. If a PING message was already sent, this means that we did
			// not receive a PONG message, so we close the connection with a
			// timeout.
			if waitingForPingReply {
				quitmsg = "Bridge: ping timeout"
				return
			}
			sendIRC = (&irc.Message{
				Prefix:  robustSession.IrcPrefix,
				Command: irc.PING,
				Params:  []string{"robustirc.bridge"},
			}).Bytes()
			waitingForPingReply = true

		case <-keepaliveToNetwork:
			sendRobust = []byte("PING keepalive")
			keepaliveToNetwork = time.After(1 * time.Minute)
		}
	}
}

// Copied from src/net/http/server.go
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}

// maybeTLSListener returns a net.Listener which possibly uses TLS, depending
// on the -tls_cert_path and -tls_key_path flag values.
func maybeTLSListener(addr string) net.Listener {
	if *tlsCertPath == "" || *tlsKeyPath == "" {
		ln, err := net.Listen("tcp", addr)
		if err != nil {
			log.Fatal(err)
		}
		return ln
	}

	tlsconfig := &tls.Config{
		Certificates: make([]tls.Certificate, 1),
	}

	var err error
	tlsconfig.Certificates[0], err = tls.LoadX509KeyPair(*tlsCertPath, *tlsKeyPath)
	if err != nil {
		log.Fatal(err)
	}

	ln, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(err)
	}

	return tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, tlsconfig)
}

func main() {
	flag.Parse()

	rand.Seed(time.Now().Unix())

	if (*network == "" && *socks == "") ||
		(*socks == "" && *listen == "") {
		log.Fatal("You must specify either -network and -listen, or -socks.")
	}

	// SOCKS and IRC
	if *socks != "" && *network != "" && *listen != "" {
		go func() {
			log.Printf("RobustIRC IRC bridge listening on %q (SOCKS)\n", *socks)
			if err := serveSocks(maybeTLSListener(*socks)); err != nil {
				log.Fatal(err)
			}
		}()
	}

	// SOCKS only
	if *socks != "" && (*network == "" || *listen == "") {
		log.Printf("RobustIRC IRC bridge listening on %q (SOCKS)\n", *socks)
		log.Fatal(serveSocks(maybeTLSListener(*socks)))
	}

	// IRC
	if *network != "" && *listen != "" {
		p := newBridge(*network)
		ln := maybeTLSListener(*listen)

		log.Printf("RobustIRC IRC bridge listening on %q (IRC)\n", *listen)

		for {
			conn, err := ln.Accept()
			if err != nil {
				log.Printf("Could not accept IRC client connection: %v\n", err)
				continue
			}
			go p.handleIRC(conn)
		}
	}
}
<|endoftext|>


<commit_before>package ext

import (
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

// Time wrap time.Time
type Time struct {
	time.Time
	isSet bool
}

var timeFormats = []string{
	time.ANSIC,
	time.UnixDate,
	time.RubyDate,
	time.RFC822,
	time.RFC822Z,
	time.RFC850,
	time.RFC1123,
	time.RFC1123Z,
	time.RFC3339,
	time.RFC3339Nano,
	time.Kitchen,
	time.Stamp,
	time.StampMilli,
	time.StampMicro,
	time.StampNano,
	"2006-01-02",
	"2006/01/02",
	"2006:01:02",
	"15:04:05",
	"2006-01-02 15:04:05",
	"2006/01/02 15:04:05",
	"2006:01:02 15:04:05",
	"15:04:05 2006-01-02",
	"15:04:05 2006/01/02",
	"15:04:05 2006:01:02",
}

func (t *Time) Decode(s string) error {
	now := time.Now()
	if s == "" {
		t.Time = now
		return nil
	}
	for _, format := range timeFormats {
		v, err := time.Parse(format, s)
		if err == nil {
			newYear, newMonth, newDay := v.Year(), v.Month(), v.Day()
			reset := false
			if newYear == 0 {
				reset = true
				newYear = now.Year()
				newMonth = now.Month()
				newDay = now.Day()
			}
			if reset {
				v = time.Date(newYear, newMonth, newDay, v.Hour(), v.Minute(), v.Second(), v.Nanosecond(), v.Location())
			}
			t.Time = v
			t.isSet = true
			return nil
		}
	}
	return fmt.Errorf("unsupported time format")
}

func (t Time) Encode() string {
	return t.Format(time.RFC3339Nano)
}

func (t Time) IsSet() bool {
	return t.isSet
}

// Duration wrap time.Duration
type Duration struct {
	time.Duration
}

func (d *Duration) Decode(s string) error {
	if i, err := strconv.ParseUint(s, 10, 64); err == nil {
		d.Duration = time.Duration(i) * time.Second
		return nil
	}
	v, err := time.ParseDuration(s)
	if err != nil {
		return err
	}
	d.Duration = v
	return nil
}

func (d Duration) Encode() string {
	return d.Duration.String()
}

// File reads data from file or stdin(if filename is empty)
type File struct {
	filename string
	data     []byte
}

func (f File) Data() []byte {
	return f.data
}

func (f File) String() string {
	if f.data == nil {
		return ""
	}
	return string(f.data)
}

func (f *File) Decode(s string) error {
	var (
		data []byte
		err  error
	)
	if s == "" {
		data, err = ioutil.ReadAll(os.Stdin)
	} else {
		data, err = ioutil.ReadFile(s)
	}
	if err != nil {
		return err
	}
	f.data = data
	f.filename = s
	return nil
}

func (f File) Encode() string {
	return f.filename
}

// Reader
type Reader struct {
	reader   io.Reader
	filename string
}

func (r *Reader) Decode(s string) error {
	if s == "" {
		r.reader = os.Stdin
		r.filename = os.Stdin.Name()
	} else {
		r.filename = s
		file, err := os.Open(s)
		if err != nil {
			return err
		}
		r.reader = file
	}
	return nil
}

// SetReader replaces the native reader
func (r *Reader) SetReader(reader io.Reader) {
	r.Close()
	r.reader = reader
	if file, ok := reader.(*os.File); ok {
		r.filename = file.Name()
	} else {
		r.filename = ""
	}
}

// Read implementes io.Reader
func (r Reader) Read(data []byte) (n int, err error) {
	if r.reader == nil {
		return os.Stdin.Read(data)
	}
	return r.reader.Read(data)
}

func (r Reader) Close() error {
	if r.reader != nil && !r.IsStdin() {
		if c, ok := r.reader.(io.Closer); ok {
			return c.Close()
		}
	}
	return nil
}

func (r Reader) Name() string {
	if r.reader == nil {
		return os.Stdin.Name()
	}
	return r.filename
}

func (r Reader) IsStdin() bool {
	if r.reader == nil {
		return true
	}
	if stdin, ok := r.reader.(*os.File); ok {
		return uintptr(unsafe.Pointer(stdin)) == uintptr(unsafe.Pointer(os.Stdin))
	}
	return false
}

// Writer
type Writer struct {
	writer   io.Writer
	filename string
}

func (w *Writer) Decode(s string) error {
	if w.writer != nil {
		return nil
	}
	if s == "" {
		w.writer = os.Stdout
		w.filename = os.Stdout.Name()
		return nil
	}
	w.filename = s
	return nil
}

// SetWriter replaces the native writer
func (w *Writer) SetWriter(writer io.Writer) {
	w.Close()
	w.writer = writer
	if file, ok := w.writer.(*os.File); ok {
		w.filename = file.Name()
	} else {
		w.filename = ""
	}
}

// Write implementes io.Writer interface
func (w *Writer) Write(data []byte) (n int, err error) {
	if w.writer == nil {
		if w.filename == "" {
			w.writer = os.Stdout
			w.filename = os.Stdout.Name()
		} else {
			file, err := os.Create(w.filename)
			if err != nil {
				return 0, err
			}
			w.writer = file
		}
	}
	return w.writer.Write(data)
}

func (w *Writer) Close() error {
	if w.writer != nil && !w.IsStdout() {
		if c, ok := w.writer.(io.Closer); ok {
			return c.Close()
		}
	}
	return nil
}

func (w *Writer) Name() string {
	if w.writer == nil {
		return os.Stdout.Name()
	}
	return w.filename
}

func (w Writer) IsStdout() bool {
	if w.writer == nil {
		return true
	}
	if stdout, ok := w.writer.(*os.File); ok {
		return uintptr(unsafe.Pointer(stdout)) == uintptr(unsafe.Pointer(os.Stdout))
	}
	return false
}

// CSV reads one csv record
type CSVRecord struct {
	raw []string
}

func (d *CSVRecord) Decode(s string) error {
	reader := csv.NewReader(strings.NewReader(s))
	record, err := reader.Read()
	if err != nil {
		return err
	}
	d.raw = record
	return nil
}

func (d CSVRecord) Strings() []string {
	return d.raw
}

func (d CSVRecord) Bools() ([]bool, error) {
	ret := make([]bool, len(d.raw))
	for _, s := range d.raw {
		s = strings.ToLower(s)
		if s == "y" || s == "yes" || s == "true" {
			ret = append(ret, true)
		} else if s == "n" || s == "no" || s == "false" {
			ret = append(ret, false)
		} else {
			v, err := strconv.Atoi(s)
			if err != nil {
				return nil, fmt.Errorf("parse %s to boolean fail", s)
			}
			ret = append(ret, v != 0)
		}
	}
	return ret, nil
}

func (d CSVRecord) Ints() ([]int64, error) {
	ret := make([]int64, len(d.raw))
	for _, s := range d.raw {
		v, err := strconv.ParseInt(s, 10, 64)
		if err != nil {
			return nil, err
		}
		ret = append(ret, v)
	}
	return ret, nil
}

func (d CSVRecord) Uints() ([]uint64, error) {
	ret := make([]uint64, len(d.raw))
	for _, s := range d.raw {
		v, err := strconv.ParseUint(s, 10, 64)
		if err != nil {
			return nil, err
		}
		ret = append(ret, v)
	}
	return ret, nil
}

func (d CSVRecord) Floats() ([]float64, error) {
	ret := make([]float64, len(d.raw))
	for _, s := range d.raw {
		v, err := strconv.ParseFloat(s, 64)
		if err != nil {
			return nil, err
		}
		ret = append(ret, v)
	}
	return ret, nil
}
<commit_msg>- [+] add read from url support, close #34<commit_after>package ext

import (
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

// Time wrap time.Time
type Time struct {
	time.Time
	isSet bool
}

var timeFormats = []string{
	time.ANSIC,
	time.UnixDate,
	time.RubyDate,
	time.RFC822,
	time.RFC822Z,
	time.RFC850,
	time.RFC1123,
	time.RFC1123Z,
	time.RFC3339,
	time.RFC3339Nano,
	time.Kitchen,
	time.Stamp,
	time.StampMilli,
	time.StampMicro,
	time.StampNano,
	"2006-01-02",
	"2006/01/02",
	"2006:01:02",
	"15:04:05",
	"2006-01-02 15:04:05",
	"2006/01/02 15:04:05",
	"2006:01:02 15:04:05",
	"15:04:05 2006-01-02",
	"15:04:05 2006/01/02",
	"15:04:05 2006:01:02",
}

func (t *Time) Decode(s string) error {
	now := time.Now()
	if s == "" {
		t.Time = now
		return nil
	}
	for _, format := range timeFormats {
		v, err := time.Parse(format, s)
		if err == nil {
			newYear, newMonth, newDay := v.Year(), v.Month(), v.Day()
			reset := false
			if newYear == 0 {
				reset = true
				newYear = now.Year()
				newMonth = now.Month()
				newDay = now.Day()
			}
			if reset {
				v = time.Date(newYear, newMonth, newDay, v.Hour(), v.Minute(), v.Second(), v.Nanosecond(), v.Location())
			}
			t.Time = v
			t.isSet = true
			return nil
		}
	}
	return fmt.Errorf("unsupported time format")
}

func (t Time) Encode() string {
	return t.Format(time.RFC3339Nano)
}

func (t Time) IsSet() bool {
	return t.isSet
}

// Duration wrap time.Duration
type Duration struct {
	time.Duration
}

func (d *Duration) Decode(s string) error {
	if i, err := strconv.ParseUint(s, 10, 64); err == nil {
		d.Duration = time.Duration(i) * time.Second
		return nil
	}
	v, err := time.ParseDuration(s)
	if err != nil {
		return err
	}
	d.Duration = v
	return nil
}

func (d Duration) Encode() string {
	return d.Duration.String()
}

// File reads data from file or stdin(if filename is empty)
type File struct {
	filename string
	data     []byte
}

func (f File) Data() []byte {
	return f.data
}

func (f File) String() string {
	if f.data == nil {
		return ""
	}
	return string(f.data)
}

func (f *File) Decode(s string) error {
	var (
		data []byte
		err  error
	)
	if s == "" {
		data, err = ioutil.ReadAll(os.Stdin)
	} else {
		data, err = ioutil.ReadFile(s)
	}
	if err != nil {
		return err
	}
	f.data = data
	f.filename = s
	return nil
}

func (f File) Encode() string {
	return f.filename
}

// Reader
type Reader struct {
	reader   io.Reader
	filename string
}

func (r *Reader) Decode(s string) error {
	if s == "" {
		r.reader = os.Stdin
		r.filename = os.Stdin.Name()
	} else if regexp.MustCompile(`(?i)^http`).MatchString(s) {
		response, err := http.Get(s)
		if err != nil {
			return err
		}
		r.reader = response.Body
	} else {
		r.filename = s
		file, err := os.Open(s)
		if err != nil {
			return err
		}
		r.reader = file
	}
	return nil
}

// SetReader replaces the native reader
func (r *Reader) SetReader(reader io.Reader) {
	r.Close()
	r.reader = reader
	if file, ok := reader.(*os.File); ok {
		r.filename = file.Name()
	} else {
		r.filename = ""
	}
}

// Read implementes io.Reader
func (r Reader) Read(data []byte) (n int, err error) {
	if r.reader == nil {
		return os.Stdin.Read(data)
	}
	return r.reader.Read(data)
}

func (r Reader) Close() error {
	if r.reader != nil && !r.IsStdin() {
		if c, ok := r.reader.(io.Closer); ok {
			return c.Close()
		}
	}
	return nil
}

func (r Reader) Name() string {
	if r.reader == nil {
		return os.Stdin.Name()
	}
	return r.filename
}

func (r Reader) IsStdin() bool {
	if r.reader == nil {
		return true
	}
	if stdin, ok := r.reader.(*os.File); ok {
		return uintptr(unsafe.Pointer(stdin)) == uintptr(unsafe.Pointer(os.Stdin))
	}
	return false
}

// Writer
type Writer struct {
	writer   io.Writer
	filename string
}

func (w *Writer) Decode(s string) error {
	if w.writer != nil {
		return nil
	}
	if s == "" {
		w.writer = os.Stdout
		w.filename = os.Stdout.Name()
		return nil
	}
	w.filename = s
	return nil
}

// SetWriter replaces the native writer
func (w *Writer) SetWriter(writer io.Writer) {
	w.Close()
	w.writer = writer
	if file, ok := w.writer.(*os.File); ok {
		w.filename = file.Name()
	} else {
		w.filename = ""
	}
}

// Write implementes io.Writer interface
func (w *Writer) Write(data []byte) (n int, err error) {
	if w.writer == nil {
		if w.filename == "" {
			w.writer = os.Stdout
			w.filename = os.Stdout.Name()
		} else {
			file, err := os.Create(w.filename)
			if err != nil {
				return 0, err
			}
			w.writer = file
		}
	}
	return w.writer.Write(data)
}

func (w *Writer) Close() error {
	if w.writer != nil && !w.IsStdout() {
		if c, ok := w.writer.(io.Closer); ok {
			return c.Close()
		}
	}
	return nil
}

func (w *Writer) Name() string {
	if w.writer == nil {
		return os.Stdout.Name()
	}
	return w.filename
}

func (w Writer) IsStdout() bool {
	if w.writer == nil {
		return true
	}
	if stdout, ok := w.writer.(*os.File); ok {
		return uintptr(unsafe.Pointer(stdout)) == uintptr(unsafe.Pointer(os.Stdout))
	}
	return false
}

// CSV reads one csv record
type CSVRecord struct {
	raw []string
}

func (d *CSVRecord) Decode(s string) error {
	reader := csv.NewReader(strings.NewReader(s))
	record, err := reader.Read()
	if err != nil {
		return err
	}
	d.raw = record
	return nil
}

func (d CSVRecord) Strings() []string {
	return d.raw
}

func (d CSVRecord) Bools() ([]bool, error) {
	ret := make([]bool, len(d.raw))
	for _, s := range d.raw {
		s = strings.ToLower(s)
		if s == "y" || s == "yes" || s == "true" {
			ret = append(ret, true)
		} else if s == "n" || s == "no" || s == "false" {
			ret = append(ret, false)
		} else {
			v, err := strconv.Atoi(s)
			if err != nil {
				return nil, fmt.Errorf("parse %s to boolean fail", s)
			}
			ret = append(ret, v != 0)
		}
	}
	return ret, nil
}

func (d CSVRecord) Ints() ([]int64, error) {
	ret := make([]int64, len(d.raw))
	for _, s := range d.raw {
		v, err := strconv.ParseInt(s, 10, 64)
		if err != nil {
			return nil, err
		}
		ret = append(ret, v)
	}
	return ret, nil
}

func (d CSVRecord) Uints() ([]uint64, error) {
	ret := make([]uint64, len(d.raw))
	for _, s := range d.raw {
		v, err := strconv.ParseUint(s, 10, 64)
		if err != nil {
			return nil, err
		}
		ret = append(ret, v)
	}
	return ret, nil
}

func (d CSVRecord) Floats() ([]float64, error) {
	ret := make([]float64, len(d.raw))
	for _, s := range d.raw {
		v, err := strconv.ParseFloat(s, 64)
		if err != nil {
			return nil, err
		}
		ret = append(ret, v)
	}
	return ret, nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.174"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.141", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<commit_msg>fnlb: 0.0.175 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.175"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.142", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.143"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.110", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<commit_msg>fnlb: 0.0.144 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.144"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.111", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<|endoftext|>


<commit_before>package lfs

import (
	"bytes"
	"encoding/base64"
	"errors"
	"github.com/github/git-lfs/vendor/_nuts/github.com/ThomsonReutersEikon/go-ntlm/ntlm"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

func (c *Configuration) ntlmClientSession(creds Creds) (ntlm.ClientSession, error) {

	if c.ntlmSession != nil {
		return c.ntlmSession, nil
	}

	splits := strings.Split(creds["username"], "\\")

	if len(splits) != 2 {
		return nil, errors.New("Your user name must be of the form DOMAIN\\user.")
	}

	var session, err = ntlm.CreateClientSession(ntlm.Version2, ntlm.ConnectionOrientedMode)

	if err != nil {
		return nil, err
	}

	session.SetUserInfo(splits[1], creds["password"], strings.ToUpper(splits[0]))

	c.ntlmSession = session

	return session, nil
}

func DoNTLMRequest(request *http.Request, retry bool) (*http.Response, error) {
	handReq, err := cloneRequest(request)
	if err != nil {
		return nil, err
	}

	res, err := InitHandShake(handReq)

	if err != nil && res == nil {
		return res, err
	}

	//If the status is 401 then we need to re-authenticate, otherwise it was successful
	if res.StatusCode == 401 {

		creds, err := getCredsForAPI(request)
		if err != nil {
			return nil, err
		}

		negotiateReq, err := cloneRequest(request)
		if err != nil {
			return nil, err
		}

		challengeMessage, err := negotiate(negotiateReq, getNegotiateMessage())
		if err != nil {
			return nil, err
		}

		challengeReq, err := cloneRequest(request)
		if err != nil {
			return nil, err
		}

		res, err := challenge(challengeReq, challengeMessage, creds)
		if err != nil {
			return res, err
		}

		//If the status is 401 then we need to re-authenticate
		if res.StatusCode == 401 && retry == true {
			return DoNTLMRequest(challengeReq, false)
		}

		saveCredentials(creds, res)

		return res, nil
	}
	return res, err
}

func InitHandShake(request *http.Request) (*http.Response, error) {
	return Config.HttpClient().Do(request)
}

func negotiate(request *http.Request, message string) ([]byte, error) {
	request.Header.Add("Authorization", message)
	var res, err = Config.HttpClient().Do(request)
	defer io.Copy(ioutil.Discard, res.Body)
	defer res.Body.Close()

	if err != nil {
		return nil, err
	}

	return parseChallengeResponse(res)
}

func challenge(request *http.Request, challengeBytes []byte, creds Creds) (*http.Response, error) {
	challenge, err := ntlm.ParseChallengeMessage(challengeBytes)

	if err != nil {
		return nil, err
	}

	session, err := Config.ntlmClientSession(creds)
	if err != nil {
		return nil, err
	}

	session.ProcessChallengeMessage(challenge)
	authenticate, err := session.GenerateAuthenticateMessage()

	if err != nil {
		return nil, err
	}

	authenticateMessage := concatS("NTLM ", base64.StdEncoding.EncodeToString(authenticate.Bytes()))
	request.Header.Add("Authorization", authenticateMessage)
	return Config.HttpClient().Do(request)
}

func parseChallengeResponse(response *http.Response) ([]byte, error) {
	header := response.Header.Get("Www-Authenticate")

	//parse out the "NTLM " at the beginning of the response
	challenge := header[5:]
	val, err := base64.StdEncoding.DecodeString(challenge)

	if err != nil {
		return nil, err
	}
	return []byte(val), nil
}

func cloneRequest(request *http.Request) (*http.Request, error) {
	var rdr1, rdr2 myReader
	var clonedReq *http.Request
	var err error

	if request.Body != nil {
		//If we have a body (POST/PUT etc.)
		//We need to do some magic to copy the request without closing the body stream

		buf, err := ioutil.ReadAll(request.Body)

		if err != nil {
			return nil, err
		}

		rdr1 = myReader{bytes.NewBuffer(buf)}
		rdr2 = myReader{bytes.NewBuffer(buf)}
		request.Body = rdr2 // OK since rdr2 implements the io.ReadCloser interface
		clonedReq, err = http.NewRequest(request.Method, request.URL.String(), rdr1)

		if err != nil {
			return nil, err
		}

	} else {
		clonedReq, err = http.NewRequest(request.Method, request.URL.String(), nil)

		if err != nil {
			return nil, err
		}
	}

	for k, v := range request.Header {
		clonedReq.Header.Add(k, v[0])
	}

	clonedReq.ContentLength = request.ContentLength

	return clonedReq, nil
}

func getNegotiateMessage() string {
	return "NTLM TlRMTVNTUAABAAAAB7IIogwADAAzAAAACwALACgAAAAKAAAoAAAAD1dJTExISS1NQUlOTk9SVEhBTUVSSUNB"
}

func concatS(ar ...string) string {

	var buffer bytes.Buffer

	for _, s := range ar {
		buffer.WriteString(s)
	}

	return buffer.String()
}

func concat(ar ...[]byte) []byte {
	return bytes.Join(ar, nil)
}

type myReader struct {
	*bytes.Buffer
}

// So that myReader implements the io.ReadCloser interface
func (m myReader) Close() error { return nil }
<commit_msg>Fix Stream Close Ordering Bug<commit_after>package lfs

import (
	"bytes"
	"encoding/base64"
	"errors"
	"github.com/github/git-lfs/vendor/_nuts/github.com/ThomsonReutersEikon/go-ntlm/ntlm"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

func (c *Configuration) ntlmClientSession(creds Creds) (ntlm.ClientSession, error) {
	if c.ntlmSession != nil {
		return c.ntlmSession, nil
	}
	splits := strings.Split(creds["username"], "\\")

	if len(splits) != 2 {
		return nil, errors.New("Your user name must be of the form DOMAIN\\user.")
	}

	session, err := ntlm.CreateClientSession(ntlm.Version2, ntlm.ConnectionOrientedMode)

	if err != nil {
		return nil, err
	}

	session.SetUserInfo(splits[1], creds["password"], strings.ToUpper(splits[0]))
	c.ntlmSession = session
	return session, nil
}

func DoNTLMRequest(request *http.Request, retry bool) (*http.Response, error) {
	handReq, err := cloneRequest(request)
	if err != nil {
		return nil, err
	}

	res, err := InitHandShake(handReq)

	if err != nil && res == nil {
		return nil, err
	}

	//If the status is 401 then we need to re-authenticate, otherwise it was successful
	if res.StatusCode == 401 {

		creds, err := getCredsForAPI(request)
		if err != nil {
			return nil, err
		}

		negotiateReq, err := cloneRequest(request)
		if err != nil {
			return nil, err
		}

		challengeMessage, err := negotiate(negotiateReq, getNegotiateMessage())
		if err != nil {
			return nil, err
		}

		challengeReq, err := cloneRequest(request)
		if err != nil {
			return nil, err
		}

		res, err := challenge(challengeReq, challengeMessage, creds)
		if err != nil {
			return nil, err
		}

		//If the status is 401 then we need to re-authenticate
		if res.StatusCode == 401 && retry == true {
			return DoNTLMRequest(challengeReq, false)
		}

		saveCredentials(creds, res)

		return res, nil
	}
	return res, nil
}

func InitHandShake(request *http.Request) (*http.Response, error) {
	return Config.HttpClient().Do(request)
}

func negotiate(request *http.Request, message string) ([]byte, error) {
	request.Header.Add("Authorization", message)
	res, err := Config.HttpClient().Do(request)

	if res == nil && err != nil{
		return nil, err
	}

	ret, err := parseChallengeResponse(res)

	if err != nil {
		return nil, err
	}

	defer res.Body.Close()
	defer io.Copy(ioutil.Discard, res.Body)

	return ret, nil;
}

func challenge(request *http.Request, challengeBytes []byte, creds Creds) (*http.Response, error) {
	challenge, err := ntlm.ParseChallengeMessage(challengeBytes)

	if err != nil {
		return nil, err
	}

	session, err := Config.ntlmClientSession(creds)
	if err != nil {
		return nil, err
	}

	session.ProcessChallengeMessage(challenge)
	authenticate, err := session.GenerateAuthenticateMessage()

	if err != nil {
		return nil, err
	}

	authenticateMessage := concatS("NTLM ", base64.StdEncoding.EncodeToString(authenticate.Bytes()))
	request.Header.Add("Authorization", authenticateMessage)
	return Config.HttpClient().Do(request)
}

func parseChallengeResponse(response *http.Response) ([]byte, error) {
	header := response.Header.Get("Www-Authenticate")

	//parse out the "NTLM " at the beginning of the response
	challenge := header[5:]
	val, err := base64.StdEncoding.DecodeString(challenge)

	if err != nil {
		return nil, err
	}
	return []byte(val), nil
}

func cloneRequest(request *http.Request) (*http.Request, error) {
	var rdr1, rdr2 myReader
	var clonedReq *http.Request
	var err error

	if request.Body != nil {
		//If we have a body (POST/PUT etc.)
		//We need to do some magic to copy the request without closing the body stream

		buf, err := ioutil.ReadAll(request.Body)

		if err != nil {
			return nil, err
		}

		rdr1 = myReader{bytes.NewBuffer(buf)}
		rdr2 = myReader{bytes.NewBuffer(buf)}
		request.Body = rdr2 // OK since rdr2 implements the io.ReadCloser interface
		clonedReq, err = http.NewRequest(request.Method, request.URL.String(), rdr1)

		if err != nil {
			return nil, err
		}

	} else {
		clonedReq, err = http.NewRequest(request.Method, request.URL.String(), nil)

		if err != nil {
			return nil, err
		}
	}

	for k, v := range request.Header {
		clonedReq.Header.Add(k, v[0])
	}

	clonedReq.ContentLength = request.ContentLength

	return clonedReq, nil
}

func getNegotiateMessage() string {
	return "NTLM TlRMTVNTUAABAAAAB7IIogwADAAzAAAACwALACgAAAAKAAAoAAAAD1dJTExISS1NQUlOTk9SVEhBTUVSSUNB"
}

func concatS(ar ...string) string {

	var buffer bytes.Buffer

	for _, s := range ar {
		buffer.WriteString(s)
	}

	return buffer.String()
}

func concat(ar ...[]byte) []byte {
	return bytes.Join(ar, nil)
}

type myReader struct {
	*bytes.Buffer
}

// So that myReader implements the io.ReadCloser interface
func (m myReader) Close() error { return nil }<|endoftext|>


<commit_before>package log

import (
	"bytes"
	"fmt"
	"strconv"
	"time"

	"github.com/fatih/color"
)

func DefaultTextFormatterForHuman(r *Record) string {
	var buf bytes.Buffer
	buf.WriteString(r.Meta.Time.Format("03:04:05 (Jan 02)"))
	buf.WriteString("  " + GetLogLevelString(r.Meta.Level) + "  ")
	args := r.Args
	if r.Format == "" {
		fmt.Fprint(&buf, args...)
	} else if len(args) > 0 {
		fmt.Fprintf(&buf, r.Format, args...)
	} else {
		buf.WriteString(r.Format)
	}
	for _, x := range r.Context() {
		fmt.Fprintf(&buf, " %s=%v ", x.Name, x.Value)
	}
	buf.WriteString("\r\n")
	return buf.String()
}

func DefaultColorTextFormatterForHuman(r *Record) string {
	var buf bytes.Buffer
	buf.WriteString(color.HiBlackString(r.Meta.Time.Format("03:04:05 (Jan 02)")))
	buf.WriteString("  " + GetLogLevelColoredString(r.Meta.Level) + "  ")
	args := r.Args
	if r.Format == "" {
		fmt.Fprint(&buf, args...)
	} else if len(args) > 0 {
		fmt.Fprintf(&buf, r.Format, args...)
	} else {
		buf.WriteString(r.Format)
	}
	for _, x := range r.Context() {
		fmt.Fprintf(&buf, " %s=%v ", x.Name, x.Value)
	}
	buf.WriteString("\r\n")
	return buf.String()
}

func DefaultTextFormatter(r *Record) string {
	var buf bytes.Buffer
	buf.WriteString(r.Meta.Time.Format(time.RFC3339))
	buf.WriteString("," + strconv.Itoa(int(r.Meta.Level)) + ",")
	args := r.Args
	if r.Format == "" {
		fmt.Fprintf(&buf, "%q", fmt.Sprint(args...))
	} else if len(args) > 0 {
		fmt.Fprintf(&buf, "%q", fmt.Sprintf(r.Format, args...))
	} else {
		fmt.Fprintf(&buf, "%q", r.Format)
	}
	ctx := r.Context()
	for _, x := range ctx {
		fmt.Fprintf(&buf, ",%q=%q", x.Name, x.Value)
	}
	buf.WriteString("\r\n")
	return buf.String()
}

func GetLogLevelString(lvl Level) string {
	switch lvl {
	case InfoLevel:
		return "info "
	case WarnLevel:
		return "warn "
	case ErrorLevel:
		return "error"
	case DebugLevel:
		return "debug"
	case TraceLevel:
		return "trace"
	}
	return " msg  "
}

func GetLogLevelColoredString(lvl Level) string {
	return GetLogLevelColoredMsg(lvl, GetLogLevelString(lvl))
}

func GetLogLevelColoredMsg(lvl Level, msg string) string {
	switch lvl {
	case InfoLevel:
		return color.BlueString(msg)
	case WarnLevel:
		return color.HiYellowString(msg)
	case ErrorLevel:
		return color.HiRedString(msg)
	case DebugLevel:
		return color.WhiteString(msg)
	case TraceLevel:
		return color.HiBlackString(msg)
	}
	return color.HiBlackString(msg)
}
<commit_msg>add: smart time log<commit_after>package log

import (
	"bytes"
	"fmt"
	"strconv"
	"time"

	"github.com/fatih/color"
)

var initTime = time.Now()

func DefaultTextFormatterForHuman(r *Record) string {
	var buf bytes.Buffer
	var timeFormat string
	t := r.Meta.Time
	if t.Sub(initTime).Hours() > 24 {
		timeFormat = "03:04:05 (Jan 02)"
	} else {
		timeFormat = "03:04:05"
	}
	buf.WriteString(color.HiBlackString(t.Format(timeFormat)))
	buf.WriteString("  " + GetLogLevelString(r.Meta.Level) + "  ")
	args := r.Args
	if r.Format == "" {
		fmt.Fprint(&buf, args...)
	} else if len(args) > 0 {
		fmt.Fprintf(&buf, r.Format, args...)
	} else {
		buf.WriteString(r.Format)
	}
	for _, x := range r.Context() {
		fmt.Fprintf(&buf, " %s=%v ", x.Name, x.Value)
	}
	buf.WriteString("\r\n")
	return buf.String()
}

func DefaultColorTextFormatterForHuman(r *Record) string {
	var buf bytes.Buffer
	t := r.Meta.Time
	var timeFormat string
	if t.Sub(initTime).Hours() > 24 {
		timeFormat = "03:04:05 (Jan 02)"
	} else {
		timeFormat = "03:04:05"
	}
	buf.WriteString(color.HiBlackString(t.Format(timeFormat)))
	buf.WriteString("  " + GetLogLevelColoredString(r.Meta.Level) + "  ")
	args := r.Args
	if r.Format == "" {
		fmt.Fprint(&buf, args...)
	} else if len(args) > 0 {
		fmt.Fprintf(&buf, r.Format, args...)
	} else {
		buf.WriteString(r.Format)
	}
	for _, x := range r.Context() {
		fmt.Fprintf(&buf, " %s=%v ", x.Name, x.Value)
	}
	buf.WriteString("\r\n")
	return buf.String()
}

func DefaultTextFormatter(r *Record) string {
	var buf bytes.Buffer
	buf.WriteString(r.Meta.Time.Format(time.RFC3339))
	buf.WriteString("," + strconv.Itoa(int(r.Meta.Level)) + ",")
	args := r.Args
	if r.Format == "" {
		fmt.Fprintf(&buf, "%q", fmt.Sprint(args...))
	} else if len(args) > 0 {
		fmt.Fprintf(&buf, "%q", fmt.Sprintf(r.Format, args...))
	} else {
		fmt.Fprintf(&buf, "%q", r.Format)
	}
	ctx := r.Context()
	for _, x := range ctx {
		fmt.Fprintf(&buf, ",%q=%q", x.Name, x.Value)
	}
	buf.WriteString("\r\n")
	return buf.String()
}

func GetLogLevelString(lvl Level) string {
	switch lvl {
	case InfoLevel:
		return "info "
	case WarnLevel:
		return "warn "
	case ErrorLevel:
		return "error"
	case DebugLevel:
		return "debug"
	case TraceLevel:
		return "trace"
	}
	return " msg  "
}

func GetLogLevelColoredString(lvl Level) string {
	return GetLogLevelColoredMsg(lvl, GetLogLevelString(lvl))
}

func GetLogLevelColoredMsg(lvl Level, msg string) string {
	switch lvl {
	case InfoLevel:
		return color.BlueString(msg)
	case WarnLevel:
		return color.HiYellowString(msg)
	case ErrorLevel:
		return color.HiRedString(msg)
	case DebugLevel:
		return color.WhiteString(msg)
	case TraceLevel:
		return color.HiBlackString(msg)
	}
	return color.HiBlackString(msg)
}
<|endoftext|>


<commit_before>// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// +build !darwin,!windows

package robotgo

import (
	"errors"
	"log"

	"github.com/BurntSushi/xgb/xproto"
	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/ewmh"
)

var xu *xgbutil.XUtil

// ActivePIDC active the window by PID,
// If args[0] > 0 on the unix platform via a xid to active
func ActivePIDC(pid int32, args ...int) {
	var hwnd int
	if len(args) > 0 {
		hwnd = args[0]

		internalActive(pid, hwnd)
		return
	}

	if xu == nil {
		var err error
		xu, err = xgbutil.NewConn()
		if err != nil {
			log.Println("xgbutil.NewConn errors is: ", err)
			return
		}
	}

	xid, err := getXidFromPid(xu, pid)
	if err != nil {
		log.Println("getXidFromPid errors is: ", err)
		return
	}

	internalActive(int32(xid), hwnd)
}

// ActivePID active the window by PID,
// If args[0] > 0 on the Windows platform via a window handle to active,
// If args[0] > 0 on the unix platform via a xid to active
func ActivePID(pid int32, args ...int) error {
	if xu == nil {
		var err error
		xu, err = xgbutil.NewConn()
		if err != nil {
			return err
		}
	}

	if len(args) > 0 {
		err := ewmh.ActiveWindowReq(xu, xproto.Window(pid))
		if err != nil {
			return err
		}

		return nil
	}

	xid, err := getXidFromPid(xu, pid)
	if err != nil {
		return err
	}

	err = ewmh.ActiveWindowReq(xu, xid)
	if err != nil {
		return err
	}

	return nil
}

func getXidFromPid(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
	windows, err := ewmh.ClientListGet(xu)
	if err != nil {
		return 0, err
	}

	for _, window := range windows {
		wmPid, err := ewmh.WmPidGet(xu, window)
		if err != nil {
			return 0, err
		}
		if uint(pid) == wmPid {
			return window, nil
		}
	}

	return 0, errors.New("failed to find a window with a matching pid")
}
<commit_msg>update robotgo unix export getXidFromPid<commit_after>// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// +build !darwin,!windows

package robotgo

import (
	"errors"
	"log"

	"github.com/BurntSushi/xgb/xproto"
	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/ewmh"
)

var xu *xgbutil.XUtil

// ActivePIDC active the window by PID,
// If args[0] > 0 on the unix platform via a xid to active
func ActivePIDC(pid int32, args ...int) {
	var hwnd int
	if len(args) > 0 {
		hwnd = args[0]

		internalActive(pid, hwnd)
		return
	}

	if xu == nil {
		var err error
		xu, err = xgbutil.NewConn()
		if err != nil {
			log.Println("xgbutil.NewConn errors is: ", err)
			return
		}
	}

	xid, err := GetXidFromPid(xu, pid)
	if err != nil {
		log.Println("GetXidFromPid errors is: ", err)
		return
	}

	internalActive(int32(xid), hwnd)
}

// ActivePID active the window by PID,
// If args[0] > 0 on the Windows platform via a window handle to active,
// If args[0] > 0 on the unix platform via a xid to active
func ActivePID(pid int32, args ...int) error {
	if xu == nil {
		var err error
		xu, err = xgbutil.NewConn()
		if err != nil {
			return err
		}
	}

	if len(args) > 0 {
		err := ewmh.ActiveWindowReq(xu, xproto.Window(pid))
		if err != nil {
			return err
		}

		return nil
	}

	xid, err := GetXidFromPid(xu, pid)
	if err != nil {
		return err
	}

	err = ewmh.ActiveWindowReq(xu, xid)
	if err != nil {
		return err
	}

	return nil
}

// GetXidFromPid get the xide from pid
func GetXidFromPid(xu *xgbutil.XUtil, pid int32) (xproto.Window, error) {
	windows, err := ewmh.ClientListGet(xu)
	if err != nil {
		return 0, err
	}

	for _, window := range windows {
		wmPid, err := ewmh.WmPidGet(xu, window)
		if err != nil {
			return 0, err
		}
		if uint(pid) == wmPid {
			return window, nil
		}
	}

	return 0, errors.New("failed to find a window with a matching pid")
}
<|endoftext|>


<commit_before>package binding

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

	"github.com/go-martini/martini"
)

var formTestCases = []formTestCase{
	{
		description:   "Happy path",
		shouldSucceed: true,
		payload:       `title=Glorious+Post+Title&content=Lorem+ipsum+dolor+sit+amet`,
		contentType:   formContentType,
		expected:      Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
	},
	{
		description:   "Happy path with interface",
		shouldSucceed: true,
		withInterface: true,
		payload:       `title=Glorious+Post+Title&content=Lorem+ipsum+dolor+sit+amet`,
		contentType:   formContentType,
		expected:      Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
	},
	{
		description:   "Empty payload",
		shouldSucceed: false,
		payload:       ``,
		contentType:   formContentType,
		expected:      Post{},
	},
	{
		description:   "Empty content type",
		shouldSucceed: false,
		payload:       `title=Glorious+Post+Title&content=Lorem+ipsum+dolor+sit+amet`,
		contentType:   ``,
		expected:      Post{},
	},
	{
		description:   "Malformed form body",
		shouldSucceed: false,
		payload:       `title=%2`,
		contentType:   formContentType,
		expected:      Post{},
	},
	{
		description:   "With nested and embedded structs",
		shouldSucceed: true,
		payload:       `title=Glorious+Post+Title&id=1&name=Matt+Holt`,
		contentType:   formContentType,
		expected:      BlogPost{Post: Post{Title: "Glorious Post Title"}, Id: 1, Author: Person{Name: "Matt Holt"}},
	},
	{
		description:   "Required embedded struct field not specified",
		shouldSucceed: false,
		payload:       `id=1&name=Matt+Holt`,
		contentType:   formContentType,
		expected:      BlogPost{Id: 1, Author: Person{Name: "Matt Holt"}},
	},
	{
		description:   "Required nested struct field not specified",
		shouldSucceed: false,
		payload:       `title=Glorious+Post+Title&id=1`,
		contentType:   formContentType,
		expected:      BlogPost{Post: Post{Title: "Glorious Post Title"}, Id: 1},
	},
	{
		description:   "Multiple values into slice",
		shouldSucceed: true,
		payload:       `title=Glorious+Post+Title&id=1&name=Matt+Holt&rating=4&rating=3&rating=5`,
		contentType:   formContentType,
		expected:      BlogPost{Post: Post{Title: "Glorious Post Title"}, Id: 1, Author: Person{Name: "Matt Holt"}, Ratings: []int{4, 3, 5}},
	},
	{
		description:   "Unexported field",
		shouldSucceed: true,
		payload:       `title=Glorious+Post+Title&id=1&name=Matt+Holt&unexported=foo`,
		contentType:   formContentType,
		expected:      BlogPost{Post: Post{Title: "Glorious Post Title"}, Id: 1, Author: Person{Name: "Matt Holt"}},
	},
	{
		description:   "Query string POST",
		shouldSucceed: true,
		payload:       `title=Glorious+Post+Title&content=Lorem+ipsum+dolor+sit+amet`,
		contentType:   formContentType,
		expected:      Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
	},
	{
		description:   "Query string",
		shouldSucceed: true,
		queryString:   "?title=Glorious+Post+Title&content=Lorem+ipsum+dolor+sit+amet",
		payload:       ``,
		contentType:   formContentType,
		expected:      Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
	},
}

func TestForm(t *testing.T) {
	for _, testCase := range formTestCases {
		performFormTest(t, Form, testCase)
	}
}

func performFormTest(t *testing.T, binder handlerFunc, testCase formTestCase) {
	httpRecorder := httptest.NewRecorder()
	m := martini.Classic()

	formTestHandler := func(actual interface{}, errs Errors) {
		if testCase.shouldSucceed && len(errs) > 0 {
			t.Errorf("'%s' should have succeeded, but there were errors (%d):\n%+v",
				testCase.description, len(errs), errs)
		} else if !testCase.shouldSucceed && len(errs) == 0 {
			t.Errorf("'%s' should have had errors, but there were none", testCase.description)
		}
		expString := fmt.Sprintf("%+v", testCase.expected)
		actString := fmt.Sprintf("%+v", actual)
		if actString != expString {
			t.Errorf("'%s': expected\n'%s'\nbut got\n'%s'",
				testCase.description, expString, actString)
		}
	}

	switch testCase.expected.(type) {
	case Post:
		if testCase.withInterface {
			m.Post(testRoute, binder(Post{}, (*modeler)(nil)), func(actual Post, iface modeler, errs Errors) {
				if actual.Title != iface.Model() {
					t.Errorf("For '%s': expected the struct to be mapped to the context as an interface",
						testCase.description)
				}
				formTestHandler(actual, errs)
			})
		} else {
			m.Post(testRoute, binder(Post{}), func(actual Post, errs Errors) {
				formTestHandler(actual, errs)
			})
		}

	case BlogPost:
		if testCase.withInterface {
			m.Post(testRoute, binder(BlogPost{}, (*modeler)(nil)), func(actual BlogPost, iface modeler, errs Errors) {
				if actual.Title != iface.Model() {
					t.Errorf("For '%s': expected the struct to be mapped to the context as an interface",
						testCase.description)
				}
				formTestHandler(actual, errs)
			})
		} else {
			m.Post(testRoute, binder(BlogPost{}), func(actual BlogPost, errs Errors) {
				formTestHandler(actual, errs)
			})
		}
	}

	req, err := http.NewRequest("POST", testRoute+testCase.queryString, strings.NewReader(testCase.payload))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", testCase.contentType)

	m.ServeHTTP(httpRecorder, req)

	switch httpRecorder.Code {
	case http.StatusNotFound:
		panic("Routing is messed up in test fixture (got 404): check methods and paths")
	case http.StatusInternalServerError:
		panic("Something bad happened on '" + testCase.description + "'")
	}
}

type (
	formTestCase struct {
		description   string
		shouldSucceed bool
		withInterface bool
		queryString   string
		payload       string
		contentType   string
		expected      interface{}
	}
)
<commit_msg>Added test case for Content-Type-less GET requests<commit_after>package binding

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

	"github.com/go-martini/martini"
)

var formTestCases = []formTestCase{
	{
		description:   "Happy path",
		shouldSucceed: true,
		payload:       `title=Glorious+Post+Title&content=Lorem+ipsum+dolor+sit+amet`,
		contentType:   formContentType,
		expected:      Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
	},
	{
		description:   "Happy path with interface",
		shouldSucceed: true,
		withInterface: true,
		payload:       `title=Glorious+Post+Title&content=Lorem+ipsum+dolor+sit+amet`,
		contentType:   formContentType,
		expected:      Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
	},
	{
		description:   "Empty payload",
		shouldSucceed: false,
		payload:       ``,
		contentType:   formContentType,
		expected:      Post{},
	},
	{
		description:   "Empty content type",
		shouldSucceed: false,
		payload:       `title=Glorious+Post+Title&content=Lorem+ipsum+dolor+sit+amet`,
		contentType:   ``,
		expected:      Post{},
	},
	{
		description:   "Malformed form body",
		shouldSucceed: false,
		payload:       `title=%2`,
		contentType:   formContentType,
		expected:      Post{},
	},
	{
		description:   "With nested and embedded structs",
		shouldSucceed: true,
		payload:       `title=Glorious+Post+Title&id=1&name=Matt+Holt`,
		contentType:   formContentType,
		expected:      BlogPost{Post: Post{Title: "Glorious Post Title"}, Id: 1, Author: Person{Name: "Matt Holt"}},
	},
	{
		description:   "Required embedded struct field not specified",
		shouldSucceed: false,
		payload:       `id=1&name=Matt+Holt`,
		contentType:   formContentType,
		expected:      BlogPost{Id: 1, Author: Person{Name: "Matt Holt"}},
	},
	{
		description:   "Required nested struct field not specified",
		shouldSucceed: false,
		payload:       `title=Glorious+Post+Title&id=1`,
		contentType:   formContentType,
		expected:      BlogPost{Post: Post{Title: "Glorious Post Title"}, Id: 1},
	},
	{
		description:   "Multiple values into slice",
		shouldSucceed: true,
		payload:       `title=Glorious+Post+Title&id=1&name=Matt+Holt&rating=4&rating=3&rating=5`,
		contentType:   formContentType,
		expected:      BlogPost{Post: Post{Title: "Glorious Post Title"}, Id: 1, Author: Person{Name: "Matt Holt"}, Ratings: []int{4, 3, 5}},
	},
	{
		description:   "Unexported field",
		shouldSucceed: true,
		payload:       `title=Glorious+Post+Title&id=1&name=Matt+Holt&unexported=foo`,
		contentType:   formContentType,
		expected:      BlogPost{Post: Post{Title: "Glorious Post Title"}, Id: 1, Author: Person{Name: "Matt Holt"}},
	},
	{
		description:   "Query string POST",
		shouldSucceed: true,
		payload:       `title=Glorious+Post+Title&content=Lorem+ipsum+dolor+sit+amet`,
		contentType:   formContentType,
		expected:      Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
	},
	{
		description:   "Query string with Content-Type (POST request)",
		shouldSucceed: true,
		queryString:   "?title=Glorious+Post+Title&content=Lorem+ipsum+dolor+sit+amet",
		payload:       ``,
		contentType:   formContentType,
		expected:      Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
	},
	{
		description:   "Query string without Content-Type (GET request)",
		shouldSucceed: true,
		method:        "GET",
		queryString:   "?title=Glorious+Post+Title&content=Lorem+ipsum+dolor+sit+amet",
		payload:       ``,
		expected:      Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
	},
}

func TestForm(t *testing.T) {
	for _, testCase := range formTestCases {
		performFormTest(t, Form, testCase)
	}
}

func performFormTest(t *testing.T, binder handlerFunc, testCase formTestCase) {
	httpRecorder := httptest.NewRecorder()
	m := martini.Classic()

	formTestHandler := func(actual interface{}, errs Errors) {
		if testCase.shouldSucceed && len(errs) > 0 {
			t.Errorf("'%s' should have succeeded, but there were errors (%d):\n%+v",
				testCase.description, len(errs), errs)
		} else if !testCase.shouldSucceed && len(errs) == 0 {
			t.Errorf("'%s' should have had errors, but there were none", testCase.description)
		}
		expString := fmt.Sprintf("%+v", testCase.expected)
		actString := fmt.Sprintf("%+v", actual)
		if actString != expString {
			t.Errorf("'%s': expected\n'%s'\nbut got\n'%s'",
				testCase.description, expString, actString)
		}
	}

	switch testCase.expected.(type) {
	case Post:
		if testCase.withInterface {
			m.Post(testRoute, binder(Post{}, (*modeler)(nil)), func(actual Post, iface modeler, errs Errors) {
				if actual.Title != iface.Model() {
					t.Errorf("For '%s': expected the struct to be mapped to the context as an interface",
						testCase.description)
				}
				formTestHandler(actual, errs)
			})
		} else {
			m.Post(testRoute, binder(Post{}), func(actual Post, errs Errors) {
				formTestHandler(actual, errs)
			})
			m.Get(testRoute, binder(Post{}), func(actual Post, errs Errors) {
				formTestHandler(actual, errs)
			})
		}

	case BlogPost:
		if testCase.withInterface {
			m.Post(testRoute, binder(BlogPost{}, (*modeler)(nil)), func(actual BlogPost, iface modeler, errs Errors) {
				if actual.Title != iface.Model() {
					t.Errorf("For '%s': expected the struct to be mapped to the context as an interface",
						testCase.description)
				}
				formTestHandler(actual, errs)
			})
		} else {
			m.Post(testRoute, binder(BlogPost{}), func(actual BlogPost, errs Errors) {
				formTestHandler(actual, errs)
			})
		}
	}

	if testCase.method == "" {
		testCase.method = "POST"
	}

	req, err := http.NewRequest(testCase.method, testRoute+testCase.queryString, strings.NewReader(testCase.payload))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", testCase.contentType)

	m.ServeHTTP(httpRecorder, req)

	switch httpRecorder.Code {
	case http.StatusNotFound:
		panic("Routing is messed up in test fixture (got 404): check methods and paths")
	case http.StatusInternalServerError:
		panic("Something bad happened on '" + testCase.description + "'")
	}
}

type (
	formTestCase struct {
		description   string
		shouldSucceed bool
		withInterface bool
		queryString   string
		payload       string
		contentType   string
		expected      interface{}
		method        string
	}
)
<|endoftext|>


<commit_before>package formats

import (
	"fmt"

	"github.com/anaminus/rbxmk"
)

// registry contains registered Formats.
var registry []func() rbxmk.Format

// register registers a Format to be returned by All.
func register(f func() rbxmk.Format) {
	registry = append(registry, f)
}

// All returns a list of Formats defined in the package.
func All() []func() rbxmk.Format {
	return registry
}

// cannotEncode returns an error indicating that v cannot be encoded.
func cannotEncode(v interface{}) error {
	return fmt.Errorf("cannot encode %T", v)
}
<commit_msg>Use Type method in error message, if possible.<commit_after>package formats

import (
	"fmt"

	"github.com/anaminus/rbxmk"
	"github.com/robloxapi/types"
)

// registry contains registered Formats.
var registry []func() rbxmk.Format

// register registers a Format to be returned by All.
func register(f func() rbxmk.Format) {
	registry = append(registry, f)
}

// All returns a list of Formats defined in the package.
func All() []func() rbxmk.Format {
	return registry
}

// cannotEncode returns an error indicating that v cannot be encoded.
func cannotEncode(v interface{}) error {
	if v, ok := v.(types.Value); ok {
		return fmt.Errorf("cannot encode %s", v.Type())
	}
	return fmt.Errorf("cannot encode %T", v)
}
<|endoftext|>