<commit_before>// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

package layers

import (
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"

	"github.com/google/gopacket"
)

// TCP is the layer for TCP headers.
type TCP struct {
	BaseLayer
	SrcPort, DstPort                           TCPPort
	Seq                                        uint32
	Ack                                        uint32
	DataOffset                                 uint8
	FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS bool
	Window                                     uint16
	Checksum                                   uint16
	Urgent                                     uint16
	sPort, dPort                               []byte
	Options                                    []TCPOption
	Padding                                    []byte
	opts                                       [4]TCPOption
	tcpipchecksum
}

// TCPOptionKind represents a TCP option code.
type TCPOptionKind uint8

const (
	TCPOptionKindEndList                         = 0
	TCPOptionKindNop                             = 1
	TCPOptionKindMSS                             = 2  // len = 4
	TCPOptionKindWindowScale                     = 3  // len = 3
	TCPOptionKindSACKPermitted                   = 4  // len = 2
	TCPOptionKindSACK                            = 5  // len = n
	TCPOptionKindEcho                            = 6  // len = 6, obsolete
	TCPOptionKindEchoReply                       = 7  // len = 6, obsolete
	TCPOptionKindTimestamps                      = 8  // len = 10
	TCPOptionKindPartialOrderConnectionPermitted = 9  // len = 2, obsolete
	TCPOptionKindPartialOrderServiceProfile      = 10 // len = 3, obsolete
	TCPOptionKindCC                              = 11 // obsolete
	TCPOptionKindCCNew                           = 12 // obsolete
	TCPOptionKindCCEcho                          = 13 // obsolete
	TCPOptionKindAltChecksum                     = 14 // len = 3, obsolete
	TCPOptionKindAltChecksumData                 = 15 // len = n, obsolete
)

func (k TCPOptionKind) String() string {
	switch k {
	case TCPOptionKindEndList:
		return "EndList"
	case TCPOptionKindNop:
		return "NOP"
	case TCPOptionKindMSS:
		return "MSS"
	case TCPOptionKindWindowScale:
		return "WindowScale"
	case TCPOptionKindSACKPermitted:
		return "SACKPermitted"
	case TCPOptionKindSACK:
		return "SACK"
	case TCPOptionKindEcho:
		return "Echo"
	case TCPOptionKindEchoReply:
		return "EchoReply"
	case TCPOptionKindTimestamps:
		return "Timestamps"
	case TCPOptionKindPartialOrderConnectionPermitted:
		return "PartialOrderConnectionPermitted"
	case TCPOptionKindPartialOrderServiceProfile:
		return "PartialOrderServiceProfile"
	case TCPOptionKindCC:
		return "CC"
	case TCPOptionKindCCNew:
		return "CCNew"
	case TCPOptionKindCCEcho:
		return "CCEcho"
	case TCPOptionKindAltChecksum:
		return "AltChecksum"
	case TCPOptionKindAltChecksumData:
		return "AltChecksumData"
	default:
		return fmt.Sprintf("Unknown(%d)", k)
	}
}

type TCPOption struct {
	OptionType   TCPOptionKind
	OptionLength uint8
	OptionData   []byte
}

func (t TCPOption) String() string {
	hd := hex.EncodeToString(t.OptionData)
	if len(hd) > 0 {
		hd = " 0x" + hd
	}
	switch t.OptionType {
	case TCPOptionKindMSS:
		return fmt.Sprintf("TCPOption(%s:%v%s)",
			t.OptionType,
			binary.BigEndian.Uint16(t.OptionData),
			hd)

	case TCPOptionKindTimestamps:
		if len(t.OptionData) == 8 {
			return fmt.Sprintf("TCPOption(%s:%v/%v%s)",
				t.OptionType,
				binary.BigEndian.Uint32(t.OptionData[:4]),
				binary.BigEndian.Uint32(t.OptionData[4:8]),
				hd)
		}
	}
	return fmt.Sprintf("TCPOption(%s:%s)", t.OptionType, hd)
}

// LayerType returns gopacket.LayerTypeTCP
func (t *TCP) LayerType() gopacket.LayerType { return LayerTypeTCP }

// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (t *TCP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	var optionLength int
	for _, o := range t.Options {
		switch o.OptionType {
		case 0, 1:
			optionLength += 1
		default:
			optionLength += 2 + len(o.OptionData)
		}
	}
	if opts.FixLengths {
		if rem := optionLength % 4; rem != 0 {
			t.Padding = lotsOfZeros[:4-rem]
		}
		t.DataOffset = uint8((len(t.Padding) + optionLength + 20) / 4)
	}
	bytes, err := b.PrependBytes(20 + optionLength + len(t.Padding))
	if err != nil {
		return err
	}
	binary.BigEndian.PutUint16(bytes, uint16(t.SrcPort))
	binary.BigEndian.PutUint16(bytes[2:], uint16(t.DstPort))
	binary.BigEndian.PutUint32(bytes[4:], t.Seq)
	binary.BigEndian.PutUint32(bytes[8:], t.Ack)
	binary.BigEndian.PutUint16(bytes[12:], t.flagsAndOffset())
	binary.BigEndian.PutUint16(bytes[14:], t.Window)
	binary.BigEndian.PutUint16(bytes[18:], t.Urgent)
	start := 20
	for _, o := range t.Options {
		bytes[start] = byte(o.OptionType)
		switch o.OptionType {
		case 0, 1:
			start++
		default:
			if opts.FixLengths {
				o.OptionLength = uint8(len(o.OptionData) + 2)
			}
			bytes[start+1] = o.OptionLength
			copy(bytes[start+2:start+len(o.OptionData)+2], o.OptionData)
			start += int(o.OptionLength)
		}
	}
	copy(bytes[start:], t.Padding)
	if opts.ComputeChecksums {
		// zero out checksum bytes in current serialization.
		bytes[16] = 0
		bytes[17] = 0
		csum, err := t.computeChecksum(b.Bytes(), IPProtocolTCP)
		if err != nil {
			return err
		}
		t.Checksum = csum
	}
	binary.BigEndian.PutUint16(bytes[16:], t.Checksum)
	return nil
}

func (t *TCP) ComputeChecksum() (uint16, error) {
	return t.computeChecksum(append(t.Contents, t.Payload...), IPProtocolTCP)
}

func (t *TCP) flagsAndOffset() uint16 {
	f := uint16(t.DataOffset) << 12
	if t.FIN {
		f |= 0x0001
	}
	if t.SYN {
		f |= 0x0002
	}
	if t.RST {
		f |= 0x0004
	}
	if t.PSH {
		f |= 0x0008
	}
	if t.ACK {
		f |= 0x0010
	}
	if t.URG {
		f |= 0x0020
	}
	if t.ECE {
		f |= 0x0040
	}
	if t.CWR {
		f |= 0x0080
	}
	if t.NS {
		f |= 0x0100
	}
	return f
}

func (tcp *TCP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	tcp.SrcPort = TCPPort(binary.BigEndian.Uint16(data[0:2]))
	tcp.sPort = data[0:2]
	tcp.DstPort = TCPPort(binary.BigEndian.Uint16(data[2:4]))
	tcp.dPort = data[2:4]
	tcp.Seq = binary.BigEndian.Uint32(data[4:8])
	tcp.Ack = binary.BigEndian.Uint32(data[8:12])
	tcp.DataOffset = data[12] >> 4
	tcp.FIN = data[13]&0x01 != 0
	tcp.SYN = data[13]&0x02 != 0
	tcp.RST = data[13]&0x04 != 0
	tcp.PSH = data[13]&0x08 != 0
	tcp.ACK = data[13]&0x10 != 0
	tcp.URG = data[13]&0x20 != 0
	tcp.ECE = data[13]&0x40 != 0
	tcp.CWR = data[13]&0x80 != 0
	tcp.NS = data[12]&0x01 != 0
	tcp.Window = binary.BigEndian.Uint16(data[14:16])
	tcp.Checksum = binary.BigEndian.Uint16(data[16:18])
	tcp.Urgent = binary.BigEndian.Uint16(data[18:20])
	tcp.Options = tcp.opts[:0]
	if tcp.DataOffset < 5 {
		return fmt.Errorf("Invalid TCP data offset %d < 5", tcp.DataOffset)
	}
	dataStart := int(tcp.DataOffset) * 4
	if dataStart > len(data) {
		df.SetTruncated()
		tcp.Payload = nil
		tcp.Contents = data
		return errors.New("TCP data offset greater than packet length")
	}
	tcp.Contents = data[:dataStart]
	tcp.Payload = data[dataStart:]
	// From here on, data points just to the header options.
	data = data[20:dataStart]
	for len(data) > 0 {
		if tcp.Options == nil {
			// Pre-allocate to avoid allocating a slice.
			tcp.Options = tcp.opts[:0]
		}
		tcp.Options = append(tcp.Options, TCPOption{OptionType: TCPOptionKind(data[0])})
		opt := &tcp.Options[len(tcp.Options)-1]
		switch opt.OptionType {
		case TCPOptionKindEndList: // End of options
			opt.OptionLength = 1
			tcp.Padding = data[1:]
			break
		case TCPOptionKindNop: // 1 byte padding
			opt.OptionLength = 1
		default:
			opt.OptionLength = data[1]
			if opt.OptionLength < 2 {
				return fmt.Errorf("Invalid TCP option length %d < 2", opt.OptionLength)
			} else if int(opt.OptionLength) > len(data) {
				return fmt.Errorf("Invalid TCP option length %d exceeds remaining %d bytes", opt.OptionLength, len(data))
			}
			opt.OptionData = data[2:opt.OptionLength]
		}
		data = data[opt.OptionLength:]
	}
	return nil
}

func (t *TCP) CanDecode() gopacket.LayerClass {
	return LayerTypeTCP
}

func (t *TCP) NextLayerType() gopacket.LayerType {
	lt := t.DstPort.LayerType()
	if lt == gopacket.LayerTypePayload {
		lt = t.SrcPort.LayerType()
	}
	return lt
}

func decodeTCP(data []byte, p gopacket.PacketBuilder) error {
	tcp := &TCP{}
	err := tcp.DecodeFromBytes(data, p)
	p.AddLayer(tcp)
	p.SetTransportLayer(tcp)
	if err != nil {
		return err
	}
	if p.DecodeOptions().DecodeStreamsAsDatagrams {
		return p.NextDecoder(tcp.NextLayerType())
	} else {
		return p.NextDecoder(gopacket.LayerTypePayload)
	}
}

func (t *TCP) TransportFlow() gopacket.Flow {
	return gopacket.NewFlow(EndpointTCPPort, t.sPort, t.dPort)
}

// For testing only
func (t *TCP) SetInternalPortsForTesting() {
	t.sPort = make([]byte, 2)
	t.dPort = make([]byte, 2)
	binary.BigEndian.PutUint16(t.sPort, uint16(t.SrcPort))
	binary.BigEndian.PutUint16(t.dPort, uint16(t.DstPort))
}
<commit_msg>Only use preallocated options in tcp, if it is nil<commit_after>// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

package layers

import (
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"

	"github.com/google/gopacket"
)

// TCP is the layer for TCP headers.
type TCP struct {
	BaseLayer
	SrcPort, DstPort                           TCPPort
	Seq                                        uint32
	Ack                                        uint32
	DataOffset                                 uint8
	FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS bool
	Window                                     uint16
	Checksum                                   uint16
	Urgent                                     uint16
	sPort, dPort                               []byte
	Options                                    []TCPOption
	Padding                                    []byte
	opts                                       [4]TCPOption
	tcpipchecksum
}

// TCPOptionKind represents a TCP option code.
type TCPOptionKind uint8

const (
	TCPOptionKindEndList                         = 0
	TCPOptionKindNop                             = 1
	TCPOptionKindMSS                             = 2  // len = 4
	TCPOptionKindWindowScale                     = 3  // len = 3
	TCPOptionKindSACKPermitted                   = 4  // len = 2
	TCPOptionKindSACK                            = 5  // len = n
	TCPOptionKindEcho                            = 6  // len = 6, obsolete
	TCPOptionKindEchoReply                       = 7  // len = 6, obsolete
	TCPOptionKindTimestamps                      = 8  // len = 10
	TCPOptionKindPartialOrderConnectionPermitted = 9  // len = 2, obsolete
	TCPOptionKindPartialOrderServiceProfile      = 10 // len = 3, obsolete
	TCPOptionKindCC                              = 11 // obsolete
	TCPOptionKindCCNew                           = 12 // obsolete
	TCPOptionKindCCEcho                          = 13 // obsolete
	TCPOptionKindAltChecksum                     = 14 // len = 3, obsolete
	TCPOptionKindAltChecksumData                 = 15 // len = n, obsolete
)

func (k TCPOptionKind) String() string {
	switch k {
	case TCPOptionKindEndList:
		return "EndList"
	case TCPOptionKindNop:
		return "NOP"
	case TCPOptionKindMSS:
		return "MSS"
	case TCPOptionKindWindowScale:
		return "WindowScale"
	case TCPOptionKindSACKPermitted:
		return "SACKPermitted"
	case TCPOptionKindSACK:
		return "SACK"
	case TCPOptionKindEcho:
		return "Echo"
	case TCPOptionKindEchoReply:
		return "EchoReply"
	case TCPOptionKindTimestamps:
		return "Timestamps"
	case TCPOptionKindPartialOrderConnectionPermitted:
		return "PartialOrderConnectionPermitted"
	case TCPOptionKindPartialOrderServiceProfile:
		return "PartialOrderServiceProfile"
	case TCPOptionKindCC:
		return "CC"
	case TCPOptionKindCCNew:
		return "CCNew"
	case TCPOptionKindCCEcho:
		return "CCEcho"
	case TCPOptionKindAltChecksum:
		return "AltChecksum"
	case TCPOptionKindAltChecksumData:
		return "AltChecksumData"
	default:
		return fmt.Sprintf("Unknown(%d)", k)
	}
}

type TCPOption struct {
	OptionType   TCPOptionKind
	OptionLength uint8
	OptionData   []byte
}

func (t TCPOption) String() string {
	hd := hex.EncodeToString(t.OptionData)
	if len(hd) > 0 {
		hd = " 0x" + hd
	}
	switch t.OptionType {
	case TCPOptionKindMSS:
		return fmt.Sprintf("TCPOption(%s:%v%s)",
			t.OptionType,
			binary.BigEndian.Uint16(t.OptionData),
			hd)

	case TCPOptionKindTimestamps:
		if len(t.OptionData) == 8 {
			return fmt.Sprintf("TCPOption(%s:%v/%v%s)",
				t.OptionType,
				binary.BigEndian.Uint32(t.OptionData[:4]),
				binary.BigEndian.Uint32(t.OptionData[4:8]),
				hd)
		}
	}
	return fmt.Sprintf("TCPOption(%s:%s)", t.OptionType, hd)
}

// LayerType returns gopacket.LayerTypeTCP
func (t *TCP) LayerType() gopacket.LayerType { return LayerTypeTCP }

// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (t *TCP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	var optionLength int
	for _, o := range t.Options {
		switch o.OptionType {
		case 0, 1:
			optionLength += 1
		default:
			optionLength += 2 + len(o.OptionData)
		}
	}
	if opts.FixLengths {
		if rem := optionLength % 4; rem != 0 {
			t.Padding = lotsOfZeros[:4-rem]
		}
		t.DataOffset = uint8((len(t.Padding) + optionLength + 20) / 4)
	}
	bytes, err := b.PrependBytes(20 + optionLength + len(t.Padding))
	if err != nil {
		return err
	}
	binary.BigEndian.PutUint16(bytes, uint16(t.SrcPort))
	binary.BigEndian.PutUint16(bytes[2:], uint16(t.DstPort))
	binary.BigEndian.PutUint32(bytes[4:], t.Seq)
	binary.BigEndian.PutUint32(bytes[8:], t.Ack)
	binary.BigEndian.PutUint16(bytes[12:], t.flagsAndOffset())
	binary.BigEndian.PutUint16(bytes[14:], t.Window)
	binary.BigEndian.PutUint16(bytes[18:], t.Urgent)
	start := 20
	for _, o := range t.Options {
		bytes[start] = byte(o.OptionType)
		switch o.OptionType {
		case 0, 1:
			start++
		default:
			if opts.FixLengths {
				o.OptionLength = uint8(len(o.OptionData) + 2)
			}
			bytes[start+1] = o.OptionLength
			copy(bytes[start+2:start+len(o.OptionData)+2], o.OptionData)
			start += int(o.OptionLength)
		}
	}
	copy(bytes[start:], t.Padding)
	if opts.ComputeChecksums {
		// zero out checksum bytes in current serialization.
		bytes[16] = 0
		bytes[17] = 0
		csum, err := t.computeChecksum(b.Bytes(), IPProtocolTCP)
		if err != nil {
			return err
		}
		t.Checksum = csum
	}
	binary.BigEndian.PutUint16(bytes[16:], t.Checksum)
	return nil
}

func (t *TCP) ComputeChecksum() (uint16, error) {
	return t.computeChecksum(append(t.Contents, t.Payload...), IPProtocolTCP)
}

func (t *TCP) flagsAndOffset() uint16 {
	f := uint16(t.DataOffset) << 12
	if t.FIN {
		f |= 0x0001
	}
	if t.SYN {
		f |= 0x0002
	}
	if t.RST {
		f |= 0x0004
	}
	if t.PSH {
		f |= 0x0008
	}
	if t.ACK {
		f |= 0x0010
	}
	if t.URG {
		f |= 0x0020
	}
	if t.ECE {
		f |= 0x0040
	}
	if t.CWR {
		f |= 0x0080
	}
	if t.NS {
		f |= 0x0100
	}
	return f
}

func (tcp *TCP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	tcp.SrcPort = TCPPort(binary.BigEndian.Uint16(data[0:2]))
	tcp.sPort = data[0:2]
	tcp.DstPort = TCPPort(binary.BigEndian.Uint16(data[2:4]))
	tcp.dPort = data[2:4]
	tcp.Seq = binary.BigEndian.Uint32(data[4:8])
	tcp.Ack = binary.BigEndian.Uint32(data[8:12])
	tcp.DataOffset = data[12] >> 4
	tcp.FIN = data[13]&0x01 != 0
	tcp.SYN = data[13]&0x02 != 0
	tcp.RST = data[13]&0x04 != 0
	tcp.PSH = data[13]&0x08 != 0
	tcp.ACK = data[13]&0x10 != 0
	tcp.URG = data[13]&0x20 != 0
	tcp.ECE = data[13]&0x40 != 0
	tcp.CWR = data[13]&0x80 != 0
	tcp.NS = data[12]&0x01 != 0
	tcp.Window = binary.BigEndian.Uint16(data[14:16])
	tcp.Checksum = binary.BigEndian.Uint16(data[16:18])
	tcp.Urgent = binary.BigEndian.Uint16(data[18:20])
	if tcp.Options == nil {
		// Pre-allocate to avoid allocating a slice.
		tcp.Options = tcp.opts[:0]
	} else {
		tcp.Options = tcp.Options[:0]
	}
	if tcp.DataOffset < 5 {
		return fmt.Errorf("Invalid TCP data offset %d < 5", tcp.DataOffset)
	}
	dataStart := int(tcp.DataOffset) * 4
	if dataStart > len(data) {
		df.SetTruncated()
		tcp.Payload = nil
		tcp.Contents = data
		return errors.New("TCP data offset greater than packet length")
	}
	tcp.Contents = data[:dataStart]
	tcp.Payload = data[dataStart:]
	// From here on, data points just to the header options.
	data = data[20:dataStart]
	for len(data) > 0 {
		tcp.Options = append(tcp.Options, TCPOption{OptionType: TCPOptionKind(data[0])})
		opt := &tcp.Options[len(tcp.Options)-1]
		switch opt.OptionType {
		case TCPOptionKindEndList: // End of options
			opt.OptionLength = 1
			tcp.Padding = data[1:]
			break
		case TCPOptionKindNop: // 1 byte padding
			opt.OptionLength = 1
		default:
			opt.OptionLength = data[1]
			if opt.OptionLength < 2 {
				return fmt.Errorf("Invalid TCP option length %d < 2", opt.OptionLength)
			} else if int(opt.OptionLength) > len(data) {
				return fmt.Errorf("Invalid TCP option length %d exceeds remaining %d bytes", opt.OptionLength, len(data))
			}
			opt.OptionData = data[2:opt.OptionLength]
		}
		data = data[opt.OptionLength:]
	}
	return nil
}

func (t *TCP) CanDecode() gopacket.LayerClass {
	return LayerTypeTCP
}

func (t *TCP) NextLayerType() gopacket.LayerType {
	lt := t.DstPort.LayerType()
	if lt == gopacket.LayerTypePayload {
		lt = t.SrcPort.LayerType()
	}
	return lt
}

func decodeTCP(data []byte, p gopacket.PacketBuilder) error {
	tcp := &TCP{}
	err := tcp.DecodeFromBytes(data, p)
	p.AddLayer(tcp)
	p.SetTransportLayer(tcp)
	if err != nil {
		return err
	}
	if p.DecodeOptions().DecodeStreamsAsDatagrams {
		return p.NextDecoder(tcp.NextLayerType())
	} else {
		return p.NextDecoder(gopacket.LayerTypePayload)
	}
}

func (t *TCP) TransportFlow() gopacket.Flow {
	return gopacket.NewFlow(EndpointTCPPort, t.sPort, t.dPort)
}

// For testing only
func (t *TCP) SetInternalPortsForTesting() {
	t.sPort = make([]byte, 2)
	t.dPort = make([]byte, 2)
	binary.BigEndian.PutUint16(t.sPort, uint16(t.SrcPort))
	binary.BigEndian.PutUint16(t.dPort, uint16(t.DstPort))
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package edwards

import (
	"math/big"

	"github.com/agl/ed25519/edwards25519"
)

var (
	// zero through eight are big.Int numbers useful in
	// elliptical curve math.
	zero  = new(big.Int).SetInt64(0)
	one   = new(big.Int).SetInt64(1)
	two   = new(big.Int).SetInt64(2)
	three = new(big.Int).SetInt64(3)
	four  = new(big.Int).SetInt64(4)
	eight = new(big.Int).SetInt64(8)

	// fieldIntSize is the size of a field element encoded
	// as bytes.
	fieldIntSize = 32
)

// feOne is the field element representation of one. This is
// also the neutral (null) element.
var feOne = edwards25519.FieldElement{
	1, 0, 0, 0, 0,
	0, 0, 0, 0, 0,
}

// feA is the field element representation of one.
var feA = edwards25519.FieldElement{
	486662, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}

// fed is the field element representation of D.
var fed = edwards25519.FieldElement{
	-10913610, 13857413, -15372611, 6949391, 114729,
	-8787816, -6275908, -3247719, -18696448, -12055116,
}

// fed2 is the field element representation of D^2.
var fed2 = edwards25519.FieldElement{
	-21827239, -5839606, -30745221, 13898782, 229458,
	15978800, -12551817, -6495438, 29715968, 9444199,
}

// feI is the field element representation of I.
var feI = edwards25519.FieldElement{
	-32595792, -7943725, 9377950, 3500415, 12389472,
	-272473, -25146209, -2005654, 326686, 11406482,
}
<commit_msg>edwards: Remove unused code.<commit_after>// Copyright (c) 2015-2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package edwards

import (
	"math/big"

	"github.com/agl/ed25519/edwards25519"
)

var (
	// zero through eight are big.Int numbers useful in
	// elliptical curve math.
	zero  = new(big.Int).SetInt64(0)
	one   = new(big.Int).SetInt64(1)
	two   = new(big.Int).SetInt64(2)
	three = new(big.Int).SetInt64(3)
	four  = new(big.Int).SetInt64(4)
	eight = new(big.Int).SetInt64(8)

	// fieldIntSize is the size of a field element encoded
	// as bytes.
	fieldIntSize = 32
)

// feOne is the field element representation of one. This is
// also the neutral (null) element.
var feOne = edwards25519.FieldElement{
	1, 0, 0, 0, 0,
	0, 0, 0, 0, 0,
}

// fed is the field element representation of D.
var fed = edwards25519.FieldElement{
	-10913610, 13857413, -15372611, 6949391, 114729,
	-8787816, -6275908, -3247719, -18696448, -12055116,
}

// fed2 is the field element representation of D^2.
var fed2 = edwards25519.FieldElement{
	-21827239, -5839606, -30745221, 13898782, 229458,
	15978800, -12551817, -6495438, 29715968, 9444199,
}

// feI is the field element representation of I.
var feI = edwards25519.FieldElement{
	-32595792, -7943725, 9377950, 3500415, 12389472,
	-272473, -25146209, -2005654, 326686, 11406482,
}
<|endoftext|>


<commit_before>package poego

type Rules struct {
	Id          int    `gorethink:"id" json:"id"`
	Name        string `gorethink:"name" json:"name"`
	Description string `gorethink:"description" json:"description"`
}

type Rule struct {
	Id          string `gorethink:"id" json:"id"`
	Name        string `gorethink:"name" json:"name"`
	Description string `gorethink:"description" json:"description"`
}

//GetLeagueRules a list of all the possible rules for a league.
func (p *Poego) GetLeagueRules() (rules []Rules, err error) {

	r := p.buildRequest("GET", "/league-rules", nil)
	err = p.makeRequest(r, &rules)

	if err != nil {
		return rules, err
	}

	return rules, err
}

//GetLeagueRule returns a specific league rule for the supplied id.
func (p *Poego) GetLeagueRule(id string) (rule Rule, err error) {

	r := p.buildRequest("GET", "/league-rules/"+id, nil)
	err = p.makeRequest(r, &rule)

	if err != nil {
		return rule, err
	}

	return rule, err
}
<commit_msg>change rules-id from int to string<commit_after>package poego

type Rules struct {
	Id          string    `gorethink:"id" json:"id"`
	Name        string `gorethink:"name" json:"name"`
	Description string `gorethink:"description" json:"description"`
}

type Rule struct {
	Id          string `gorethink:"id" json:"id"`
	Name        string `gorethink:"name" json:"name"`
	Description string `gorethink:"description" json:"description"`
}

//GetLeagueRules a list of all the possible rules for a league.
func (p *Poego) GetLeagueRules() (rules []Rules, err error) {

	r := p.buildRequest("GET", "/league-rules", nil)
	err = p.makeRequest(r, &rules)

	if err != nil {
		return rules, err
	}

	return rules, err
}

//GetLeagueRule returns a specific league rule for the supplied id.
func (p *Poego) GetLeagueRule(id string) (rule Rule, err error) {

	r := p.buildRequest("GET", "/league-rules/"+id, nil)
	err = p.makeRequest(r, &rule)

	if err != nil {
		return rule, err
	}

	return rule, err
}
<|endoftext|>


<commit_before>package fastping

import (
	"net"
	"sync"
	"testing"
	"time"
)

type addHostTest struct {
	host   string
	addr   *net.IPAddr
	expect bool
}

var addHostTests = []addHostTest{
	{host: "127.0.0.1", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: true},
	{host: "localhost", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: false},
}

func TestAddIP(t *testing.T) {
	p := NewPinger()

	for _, tt := range addHostTests {
		if ok := p.AddIP(tt.host); ok != nil {
			if tt.expect != false {
				t.Errorf("AddIP failed: got %v, expected %v", ok, tt.expect)
			}
		}
	}
	for _, tt := range addHostTests {
		if tt.expect {
			if !p.addrs[tt.host].IP.Equal(tt.addr.IP) {
				t.Errorf("AddIP didn't save IPAddr: %v", tt.host)
			}
		}
	}
}

func TestRun(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	if err := p.AddIP("127.0.0.100"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	found1, found100 := false, false
	called, idle := false, false
	err := p.AddHandler("receive", func(ip *net.IPAddr, d time.Duration) {
		called = true
		if ip.String() == "127.0.0.1" {
			found1 = true
		} else if ip.String() == "127.0.0.100" {
			found100 = true
		}
	})
	if err != nil {
		t.Fatalf("Failed to add receive hander: %v", err)
	}

	err = p.AddHandler("idle", func() {
		idle = true
	})
	if err != nil {
		t.Fatalf("Failed to add idle handler: %v", err)
	}

	err = p.Run()
	if err != nil {
		t.Fatalf("Pinger returns error: %v", err)
	}
	if !called {
		t.Fatalf("Pinger didn't get any responses")
	}
	if !idle {
		t.Fatalf("Pinger didn't call OnIdle function")
	}
	if !found1 {
		t.Fatalf("Pinger `127.0.0.1` didn't respond")
	}
	if found100 {
		t.Fatalf("Pinger `127.0.0.100` responded")
	}
}

func TestMultiRun(t *testing.T) {
	p1 := NewPinger()
	p2 := NewPinger()

	if err := p1.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 1 failed: %v", err)
	}

	if err := p2.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 1 failed: %v", err)
	}

	var mu sync.Mutex
	res1 := 0
	err := p1.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res1++
		mu.Unlock()
	})
	if err != nil {
		t.Fatalf("Failed to add receive hander: %v", err)
	}

	res2 := 0
	err = p2.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res2++
		mu.Unlock()
	})
	if err != nil {
		t.Fatalf("Failed to add idle handler: %v", err)
	}

	p1.MaxRTT, p2.MaxRTT = time.Millisecond*100, time.Millisecond*100

	if err := p1.Run(); err != nil {
		t.Fatalf("Pinger 1 returns error: %v", err)
	}
	if res1 == 0 {
		t.Fatalf("Pinger 1 didn't get any responses")
	}
	if res2 > 0 {
		t.Fatalf("Pinger 2 got response")
	}

	res1, res2 = 0, 0
	if err := p2.Run(); err != nil {
		t.Fatalf("Pinger 2 returns error: %v", err)
	}
	if res1 > 0 {
		t.Fatalf("Pinger 1 got response")
	}
	if res2 == 0 {
		t.Fatalf("Pinger 2 didn't get any responses")
	}

	res1, res2 = 0, 0
	errch1, errch2 := make(chan error), make(chan error)
	go func(ch chan error) {
		err := p1.Run()
		if err != nil {
			ch <- err
		}
	}(errch1)
	go func(ch chan error) {
		err := p2.Run()
		if err != nil {
			ch <- err
		}
	}(errch2)
	ticker := time.NewTicker(time.Millisecond * 200)
	select {
	case err := <-errch1:
		t.Fatalf("Pinger 1 returns error: %v", err)
	case err := <-errch2:
		t.Fatalf("Pinger 2 returns error: %v", err)
	case <-ticker.C:
		break
	}
	mu.Lock()
	defer mu.Unlock()
	if res1 != 1 {
		t.Fatalf("Pinger 1 didn't get correct response")
	}
	if res2 != 1 {
		t.Fatalf("Pinger 2 didn't get correct response")
	}
}

func TestRunLoop(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}
	p.MaxRTT = time.Millisecond * 100

	recvCount, idleCount := 0, 0
	err := p.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		recvCount++
	})
	if err != nil {
		t.Fatalf("Failed to add receive handler: %v", err)
	}

	err = p.AddHandler("idle", func() {
		idleCount++
	})
	if err != nil {
		t.Fatalf("Failed to add idle handler: %v", err)
	}

	wait := make(chan bool)
	quit, errch := p.RunLoop()
	ticker := time.NewTicker(time.Millisecond * 250)
loop:
	for {
		select {
		case err := <-errch:
			t.Fatalf("Pinger returns error %v", err)
		case <-ticker.C:
			ticker.Stop()
			quit <- wait
		case <-wait:
			break loop
		}
	}

	if recvCount < 2 {
		t.Fatalf("Pinger receive count less than 2")
	}
	if idleCount < 2 {
		t.Fatalf("Pinger idle count less than 2")
	}
}

func TestTimeToBytes(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	expect := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	for i := 0; i < 8; i++ {
		if b[i] != expect[i] {
			t.Errorf("timeToBytes failed: got %v, expected: %v", b, expect)
			break
		}
	}
}

func TestBytesToTime(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	b := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	expect, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	tm := bytesToTime(b)
	if !tm.Equal(expect) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm.UTC(), expect.UTC())
	}
}

func TestTimeToBytesToTime(t *testing.T) {
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	tm2 := bytesToTime(b)
	if !tm.Equal(tm2) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm2.UTC(), tm.UTC())
	}
}
<commit_msg>Fix a wrong test error message<commit_after>package fastping

import (
	"net"
	"sync"
	"testing"
	"time"
)

type addHostTest struct {
	host   string
	addr   *net.IPAddr
	expect bool
}

var addHostTests = []addHostTest{
	{host: "127.0.0.1", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: true},
	{host: "localhost", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: false},
}

func TestAddIP(t *testing.T) {
	p := NewPinger()

	for _, tt := range addHostTests {
		if ok := p.AddIP(tt.host); ok != nil {
			if tt.expect != false {
				t.Errorf("AddIP failed: got %v, expected %v", ok, tt.expect)
			}
		}
	}
	for _, tt := range addHostTests {
		if tt.expect {
			if !p.addrs[tt.host].IP.Equal(tt.addr.IP) {
				t.Errorf("AddIP didn't save IPAddr: %v", tt.host)
			}
		}
	}
}

func TestRun(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	if err := p.AddIP("127.0.0.100"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	found1, found100 := false, false
	called, idle := false, false
	err := p.AddHandler("receive", func(ip *net.IPAddr, d time.Duration) {
		called = true
		if ip.String() == "127.0.0.1" {
			found1 = true
		} else if ip.String() == "127.0.0.100" {
			found100 = true
		}
	})
	if err != nil {
		t.Fatalf("Failed to add receive hander: %v", err)
	}

	err = p.AddHandler("idle", func() {
		idle = true
	})
	if err != nil {
		t.Fatalf("Failed to add idle handler: %v", err)
	}

	err = p.Run()
	if err != nil {
		t.Fatalf("Pinger returns error: %v", err)
	}
	if !called {
		t.Fatalf("Pinger didn't get any responses")
	}
	if !idle {
		t.Fatalf("Pinger didn't call OnIdle function")
	}
	if !found1 {
		t.Fatalf("Pinger `127.0.0.1` didn't respond")
	}
	if found100 {
		t.Fatalf("Pinger `127.0.0.100` responded")
	}
}

func TestMultiRun(t *testing.T) {
	p1 := NewPinger()
	p2 := NewPinger()

	if err := p1.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 1 failed: %v", err)
	}

	if err := p2.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 2 failed: %v", err)
	}

	var mu sync.Mutex
	res1 := 0
	err := p1.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res1++
		mu.Unlock()
	})
	if err != nil {
		t.Fatalf("Failed to add receive hander: %v", err)
	}

	res2 := 0
	err = p2.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res2++
		mu.Unlock()
	})
	if err != nil {
		t.Fatalf("Failed to add idle handler: %v", err)
	}

	p1.MaxRTT, p2.MaxRTT = time.Millisecond*100, time.Millisecond*100

	if err := p1.Run(); err != nil {
		t.Fatalf("Pinger 1 returns error: %v", err)
	}
	if res1 == 0 {
		t.Fatalf("Pinger 1 didn't get any responses")
	}
	if res2 > 0 {
		t.Fatalf("Pinger 2 got response")
	}

	res1, res2 = 0, 0
	if err := p2.Run(); err != nil {
		t.Fatalf("Pinger 2 returns error: %v", err)
	}
	if res1 > 0 {
		t.Fatalf("Pinger 1 got response")
	}
	if res2 == 0 {
		t.Fatalf("Pinger 2 didn't get any responses")
	}

	res1, res2 = 0, 0
	errch1, errch2 := make(chan error), make(chan error)
	go func(ch chan error) {
		err := p1.Run()
		if err != nil {
			ch <- err
		}
	}(errch1)
	go func(ch chan error) {
		err := p2.Run()
		if err != nil {
			ch <- err
		}
	}(errch2)
	ticker := time.NewTicker(time.Millisecond * 200)
	select {
	case err := <-errch1:
		t.Fatalf("Pinger 1 returns error: %v", err)
	case err := <-errch2:
		t.Fatalf("Pinger 2 returns error: %v", err)
	case <-ticker.C:
		break
	}
	mu.Lock()
	defer mu.Unlock()
	if res1 != 1 {
		t.Fatalf("Pinger 1 didn't get correct response")
	}
	if res2 != 1 {
		t.Fatalf("Pinger 2 didn't get correct response")
	}
}

func TestRunLoop(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}
	p.MaxRTT = time.Millisecond * 100

	recvCount, idleCount := 0, 0
	err := p.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		recvCount++
	})
	if err != nil {
		t.Fatalf("Failed to add receive handler: %v", err)
	}

	err = p.AddHandler("idle", func() {
		idleCount++
	})
	if err != nil {
		t.Fatalf("Failed to add idle handler: %v", err)
	}

	wait := make(chan bool)
	quit, errch := p.RunLoop()
	ticker := time.NewTicker(time.Millisecond * 250)
loop:
	for {
		select {
		case err := <-errch:
			t.Fatalf("Pinger returns error %v", err)
		case <-ticker.C:
			ticker.Stop()
			quit <- wait
		case <-wait:
			break loop
		}
	}

	if recvCount < 2 {
		t.Fatalf("Pinger receive count less than 2")
	}
	if idleCount < 2 {
		t.Fatalf("Pinger idle count less than 2")
	}
}

func TestTimeToBytes(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	expect := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	for i := 0; i < 8; i++ {
		if b[i] != expect[i] {
			t.Errorf("timeToBytes failed: got %v, expected: %v", b, expect)
			break
		}
	}
}

func TestBytesToTime(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	b := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	expect, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	tm := bytesToTime(b)
	if !tm.Equal(expect) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm.UTC(), expect.UTC())
	}
}

func TestTimeToBytesToTime(t *testing.T) {
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	tm2 := bytesToTime(b)
	if !tm.Equal(tm2) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm2.UTC(), tm.UTC())
	}
}
<|endoftext|>


<commit_before>// HTTP server that takes JSON feedback for the Alkomat 3000 app and turns it into a neat
// e-mail forwarded to the maintainer's address.
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/smtp"
	"strings"
	"time"
)

func main() {
	if FromAddr == "foo@example.com" {
		log.Fatal("Please set the constants in config.go and recompile")
	}

	if Passwd == "" {
		log.Fatal("Please enter the password in config.go and recompile")
	}

	http.HandleFunc("/", rootHandler)

	log.Println("Starting server on port", Port)
	log.Fatal(http.ListenAndServeTLS(":"+Port, CertificatePath, PrivateKeyPath, nil))
}

type Device struct {
	OSVer    string
	OSAPILvl int
	Device   string
	Model    string
}

func (d Device) String() string {
	return fmt.Sprintf("\tOS version: %s (API %d)\n\tDevice: %s\n\tModel: %s\n",
		d.OSVer, d.OSAPILvl, d.Device, d.Model)
}

type Feedback struct {
	Device     Device
	AppInfo    string
	LogTrace   string
	Sender     string
	SenderMail string
	Message    string
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	body, _ := ioutil.ReadAll(r.Body)
	fbstr := string(body)

	agent := r.Header.Get("user-agent")
	log.Println("Received feedback from", agent, "(", r.RemoteAddr, ")")

	decoder := json.NewDecoder(strings.NewReader(fbstr))
	var feedback Feedback
	err := decoder.Decode(&feedback)
	if err != nil {
		log.Println("JSON decode error:", err)
	}

	// Only show sender if one is mentioned.
	senderstr := ""
	if feedback.Sender != "" {
		senderstr = fmt.Sprintf("Sender: %s <%s>", feedback.Sender, feedback.SenderMail)
	}

	// The message written by the app user is indented by a single tab for clearer separation.
	msg := fmt.Sprintf("Alkomat 3000 Feedback\n%s\nDevice:\n%v\nApp: %s\nMessage:\n\n\t",
		senderstr, feedback.Device, feedback.AppInfo)
	msg += strings.Replace(feedback.Message, "\n", "\n\t", -1) + "\n"
	msg += "\nEnd of message\n"
	msg += "Log trace:\n" + feedback.LogTrace + "\n"

	err = sendMail(Subject, msg)
	if err != nil {
		log.Println("couldn't send mail:", err)
		return
	}
}

// sendMail sends a mail with the given subject and content. The content must have Unix
// newlines (\n) and end in a newline. These newlines will be converted to SMTP's CRLF
// automatically.
func sendMail(subject, content string) error {
	auth := smtp.PlainAuth("", FromAddr, Passwd, SMTPSrv)
	to := []string{ToAddr}
	date := time.Now().Format(time.RFC822Z)

	header := fmt.Sprintf("Date: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\n", date, FromAddr, ToAddr, subject)
	body := strings.Replace(content, "\n", "\r\n", -1)
	msg := []byte(header + "\r\n" + body)

	return smtp.SendMail(SMTPSrv+":587", auth, FromAddr, to, msg)
}
<commit_msg>Update main.go<commit_after>// HTTP server that takes JSON feedback for the Alkomat 3000 app and turns it into a neat
// e-mail forwarded to the maintainer's address.
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/smtp"
	"strings"
	"time"
)

func main() {
	if FromAddr == "foo@example.com" {
		log.Fatal("Please set the constants in config.go and recompile")
	}

	if Passwd == "" {
		log.Fatal("Please enter the password in config.go and recompile")
	}

	http.HandleFunc("/", rootHandler)

	log.Println("Starting server on port", Port)
	log.Fatal(http.ListenAndServeTLS(":"+Port, CertificatePath, PrivateKeyPath, nil))
}

type Device struct {
	OSVer    string
	OSAPILvl int
	Device   string
	Model    string
}

func (d Device) String() string {
	return fmt.Sprintf("\tOS version: %s (API %d)\n\tDevice: %s\n\tModel: %s\n",
		d.OSVer, d.OSAPILvl, d.Device, d.Model)
}

type Feedback struct {
	Device     Device
	AppInfo    string
	LogTrace   string
	Sender     string
	SenderMail string
	Message    string
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	body, _ := ioutil.ReadAll(r.Body)
	fbstr := string(body)

	agent := r.Header.Get("user-agent")
	log.Println("Received feedback from", agent, "(", r.RemoteAddr, ")")

	decoder := json.NewDecoder(strings.NewReader(fbstr))
	var feedback Feedback
	err := decoder.Decode(&feedback)
	if err != nil {
		log.Println("JSON decode error:", err)
	}

	// Only show sender if one is mentioned.
	senderstr := ""
	if feedback.Sender != "" {
		senderstr = fmt.Sprintf("Sender: %s <%s>", feedback.Sender, feedback.SenderMail)
	}

	// The message written by the app user is indented by a single tab for clearer separation.
	msg := fmt.Sprintf("Alkomat 3000 Feedback\n%s\nDevice:\n%v\nApp: %s\nMessage:\n\n\t",
		senderstr, feedback.Device, feedback.AppInfo)
	msg += strings.Replace(feedback.Message, "\n", "\n\t", -1) + "\n"
	msg += "\nEnd of message\n"
	msg += "Log trace:\n" + feedback.LogTrace + "\n"

	err = sendMail(Subject, msg)
	if err != nil {
		log.Println("couldn't send mail:", err)
		return
	}
}

// sendMail sends a mail with the given subject and content. The content must have Unix
// newlines (\n) and end in a newline. These newlines will be converted to SMTP's CRLF
// automatically.
func sendMail(subject, content string) error {
	auth := smtp.PlainAuth("", FromAddr, Passwd, SMTPSrv)
	to := []string{ToAddr}
	date := time.Now().Format(time.RFC822Z)

	header := fmt.Sprintf("Date: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\n", date, FromAddr, ToAddr, subject)
	body := strings.Replace(content, "\n", "\r\n", -1)
	msg := []byte(header + "\r\n" + body)

	return smtp.SendMail(SMTPSrv+":"+SMTPPort, auth, FromAddr, to, msg)
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 main contains a simple command line tool for Places API Text Search
// Documentation: https://developers.google.com/places/web-service/search#TextSearchRequests
package main

import (
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/kr/pretty"
	"golang.org/x/net/context"
	"googlemaps.github.io/maps"
)

var (
	apiKey    = flag.String("key", "", "API Key for using Google Maps API.")
	clientID  = flag.String("client_id", "", "ClientID for Maps for Work API access.")
	signature = flag.String("signature", "", "Signature for Maps for Work API access.")
	location  = flag.String("location", "", "The latitude/longitude around which to retrieve place information. This must be specified as latitude,longitude.")
	radius    = flag.Uint("radius", 0, "Defines the distance (in meters) within which to bias place results. The maximum allowed radius is 50,000 meters.")
	keyword   = flag.String("keyword", "", "Specifies the language in which to return results. Optional.")
	language  = flag.String("language", "", "The language in which to return results.")
	minPrice  = flag.String("minprice", "", "Restricts results to only those places within the specified price level.")
	maxPrice  = flag.String("maxprice", "", "Restricts results to only those places within the specified price level.")
	name      = flag.String("name", "", "One or more terms to be matched against the names of places, separated with a space character.")
	openNow   = flag.Bool("open_now", false, "Restricts results to only those places that are open for business at the time the query is sent.")
	rankBy    = flag.String("rankby", "", "Specifies the order in which results are listed. Valid values are prominence or distance.")
	placeType = flag.String("type", "", "Restricts the results to places matching the specified type.")
	pageToken = flag.String("pagetoken", "", "Set to retrieve the next next page of results.")
)

func usageAndExit(msg string) {
	fmt.Fprintln(os.Stderr, msg)
	fmt.Println("Flags:")
	flag.PrintDefaults()
	os.Exit(2)
}

func check(err error) {
	if err != nil {
		log.Fatalf("fatal error: %s", err)
	}
}

func main() {
	flag.Parse()

	var client *maps.Client
	var err error
	if *apiKey != "" {
		client, err = maps.NewClient(maps.WithAPIKey(*apiKey))
	} else if *clientID != "" || *signature != "" {
		client, err = maps.NewClient(maps.WithClientIDAndSignature(*clientID, *signature))
	} else {
		usageAndExit("Please specify an API Key, or Client ID and Signature.")
	}
	check(err)

	r := &maps.NearbySearchRequest{
		Radius:    *radius,
		Keyword:   *keyword,
		Language:  *language,
		Name:      *name,
		OpenNow:   *openNow,
		PageToken: *pageToken,
	}

	parseLocation(*location, r)
	parsePriceLevels(*minPrice, *maxPrice, r)
	parseRankBy(*rankBy, r)
	parsePlaceType(*placeType, r)

	resp, err := client.NearbySearch(context.Background(), r)
	check(err)

	pretty.Println(resp)
}

func parseLocation(location string, r *maps.NearbySearchRequest) {
	if location != "" {
		l, err := maps.ParseLatLng(location)
		check(err)
		r.Location = &l
	}
}

func parsePriceLevel(priceLevel string) maps.PriceLevel {
	switch priceLevel {
	case "0":
		return maps.PriceLevelFree
	case "1":
		return maps.PriceLevelInexpensive
	case "2":
		return maps.PriceLevelModerate
	case "3":
		return maps.PriceLevelExpensive
	case "4":
		return maps.PriceLevelVeryExpensive
	default:
		usageAndExit(fmt.Sprintf("Unknown price level: '%s'", priceLevel))
	}
	return maps.PriceLevelFree
}

func parsePriceLevels(minPrice string, maxPrice string, r *maps.NearbySearchRequest) {
	if minPrice != "" {
		r.MinPrice = parsePriceLevel(minPrice)
	}

	if maxPrice != "" {
		r.MaxPrice = parsePriceLevel(minPrice)
	}
}

func parseRankBy(rankBy string, r *maps.NearbySearchRequest) {
	switch rankBy {
	case "prominence":
		r.RankBy = maps.RankByProminence
		return
	case "distance":
		r.RankBy = maps.RankByDistance
		return
	case "":
		return
	default:
		usageAndExit(fmt.Sprintf("Unknown rank by: \"%v\"", rankBy))
	}
}

func parsePlaceType(placeType string, r *maps.NearbySearchRequest) {
	if placeType != "" {
		t, err := maps.ParsePlaceType(placeType)
		if err != nil {
			usageAndExit(fmt.Sprintf("Unknown place type \"%v\"", placeType))
		}

		r.Type = t
	}
}
<commit_msg>Fix small typo - correct pagetoken flag description<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 main contains a simple command line tool for Places API Text Search
// Documentation: https://developers.google.com/places/web-service/search#TextSearchRequests
package main

import (
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/kr/pretty"
	"golang.org/x/net/context"
	"googlemaps.github.io/maps"
)

var (
	apiKey    = flag.String("key", "", "API Key for using Google Maps API.")
	clientID  = flag.String("client_id", "", "ClientID for Maps for Work API access.")
	signature = flag.String("signature", "", "Signature for Maps for Work API access.")
	location  = flag.String("location", "", "The latitude/longitude around which to retrieve place information. This must be specified as latitude,longitude.")
	radius    = flag.Uint("radius", 0, "Defines the distance (in meters) within which to bias place results. The maximum allowed radius is 50,000 meters.")
	keyword   = flag.String("keyword", "", "Specifies the language in which to return results. Optional.")
	language  = flag.String("language", "", "The language in which to return results.")
	minPrice  = flag.String("minprice", "", "Restricts results to only those places within the specified price level.")
	maxPrice  = flag.String("maxprice", "", "Restricts results to only those places within the specified price level.")
	name      = flag.String("name", "", "One or more terms to be matched against the names of places, separated with a space character.")
	openNow   = flag.Bool("open_now", false, "Restricts results to only those places that are open for business at the time the query is sent.")
	rankBy    = flag.String("rankby", "", "Specifies the order in which results are listed. Valid values are prominence or distance.")
	placeType = flag.String("type", "", "Restricts the results to places matching the specified type.")
	pageToken = flag.String("pagetoken", "", "Set to retrieve the next page of results.")
)

func usageAndExit(msg string) {
	fmt.Fprintln(os.Stderr, msg)
	fmt.Println("Flags:")
	flag.PrintDefaults()
	os.Exit(2)
}

func check(err error) {
	if err != nil {
		log.Fatalf("fatal error: %s", err)
	}
}

func main() {
	flag.Parse()

	var client *maps.Client
	var err error
	if *apiKey != "" {
		client, err = maps.NewClient(maps.WithAPIKey(*apiKey))
	} else if *clientID != "" || *signature != "" {
		client, err = maps.NewClient(maps.WithClientIDAndSignature(*clientID, *signature))
	} else {
		usageAndExit("Please specify an API Key, or Client ID and Signature.")
	}
	check(err)

	r := &maps.NearbySearchRequest{
		Radius:    *radius,
		Keyword:   *keyword,
		Language:  *language,
		Name:      *name,
		OpenNow:   *openNow,
		PageToken: *pageToken,
	}

	parseLocation(*location, r)
	parsePriceLevels(*minPrice, *maxPrice, r)
	parseRankBy(*rankBy, r)
	parsePlaceType(*placeType, r)

	resp, err := client.NearbySearch(context.Background(), r)
	check(err)

	pretty.Println(resp)
}

func parseLocation(location string, r *maps.NearbySearchRequest) {
	if location != "" {
		l, err := maps.ParseLatLng(location)
		check(err)
		r.Location = &l
	}
}

func parsePriceLevel(priceLevel string) maps.PriceLevel {
	switch priceLevel {
	case "0":
		return maps.PriceLevelFree
	case "1":
		return maps.PriceLevelInexpensive
	case "2":
		return maps.PriceLevelModerate
	case "3":
		return maps.PriceLevelExpensive
	case "4":
		return maps.PriceLevelVeryExpensive
	default:
		usageAndExit(fmt.Sprintf("Unknown price level: '%s'", priceLevel))
	}
	return maps.PriceLevelFree
}

func parsePriceLevels(minPrice string, maxPrice string, r *maps.NearbySearchRequest) {
	if minPrice != "" {
		r.MinPrice = parsePriceLevel(minPrice)
	}

	if maxPrice != "" {
		r.MaxPrice = parsePriceLevel(minPrice)
	}
}

func parseRankBy(rankBy string, r *maps.NearbySearchRequest) {
	switch rankBy {
	case "prominence":
		r.RankBy = maps.RankByProminence
		return
	case "distance":
		r.RankBy = maps.RankByDistance
		return
	case "":
		return
	default:
		usageAndExit(fmt.Sprintf("Unknown rank by: \"%v\"", rankBy))
	}
}

func parsePlaceType(placeType string, r *maps.NearbySearchRequest) {
	if placeType != "" {
		t, err := maps.ParsePlaceType(placeType)
		if err != nil {
			usageAndExit(fmt.Sprintf("Unknown place type \"%v\"", placeType))
		}

		r.Type = t
	}
}
<|endoftext|>


<commit_before>package fetch

import (
	"encoding/json"
	"io"
	"net/http"
	"net/url"

	"github.com/juju/persistent-cookiejar"
	"github.com/slotix/dataflowkit/splash"
	"github.com/slotix/dataflowkit/storage"
	"github.com/spf13/viper"
	"golang.org/x/net/publicsuffix"
)

// Service defines Fetch service interface
type Service interface {
	Response(req FetchRequester) (FetchResponser, error)
	Fetch(req FetchRequester) (io.ReadCloser, error)
}

// FetchService implements service with empty struct
type FetchService struct {
}

// ServiceMiddleware defines a middleware for a Fetch service
type ServiceMiddleware func(Service) Service

//Response returns splash.Response
func (fs FetchService) Response(req FetchRequester) (FetchResponser, error) {

	var err error
	var fetcher Fetcher
	switch req.(type) {
	case BaseFetcherRequest:
		fetcher, err = NewFetcher(Base)
	case splash.Request:
		fetcher, err = NewFetcher(Splash)
	default:
		panic("invalid fetcher request")
	}

	if err != nil {
		logger.Error(err)
	}
	storageType, err = storage.TypeString(viper.GetString("STORAGE_TYPE"))
	if err != nil {
		return nil, err
	}
	s := storage.NewStore(storageType)
	cookies, _ := s.Read(req.GetUserToken())
	jarOpts := &cookiejar.Options{PublicSuffixList: publicsuffix.List}
	jar, err := cookiejar.New(jarOpts)
	if err != nil {
		logger.Error("Failed to create Cookie Jar")

	}
	cArr := []*http.Cookie{}
	if len(cookies) != 0 {
		err = json.Unmarshal(cookies, &cArr)
		if err != nil {
			return nil, err
		}
		u, err := url.Parse(req.GetURL())
		if err != nil {
			return nil, err
		}
		tempCarr := []*http.Cookie{}
		for i := 0; i < len(cArr); i++ {
			c := cArr[i]
			if u.Host == c.Domain {
				tempCarr = append(tempCarr, c)
				cArr = append(cArr[:i], cArr[i+1:]...)
				i--
			}
		}
		jar.SetCookies(u, tempCarr)
	}
	fetcher.SetCookieJar(jar)
	//res, err := fetcher.Fetch(req)
	res, err := fetcher.Response(req)
	if err != nil {
		return nil, err
	}
	jar = fetcher.GetCookieJar()
	cArr = append(cArr, jar.AllCookies()...)
	cookies, err = json.Marshal(cArr)
	logger.Info(string(cookies))
	if err != nil {
		return nil, err
	}
	err = s.Write(req.GetUserToken(), cookies, 0)
	if err != nil {
		return nil, err
	}
	return res, nil
}

//Fetch downloads web page content and returns it
func (fs FetchService) Fetch(req FetchRequester) (io.ReadCloser, error) {
	res, err := fs.Response(req)
	if err != nil {
		return nil, err
	}
	return res.GetHTML()
}
<commit_msg>ignore cookies stuff for anonymous users and robots.txt requests<commit_after>package fetch

import (
	"encoding/json"
	"io"
	"net/http"
	"net/url"

	"github.com/juju/persistent-cookiejar"
	"github.com/slotix/dataflowkit/splash"
	"github.com/slotix/dataflowkit/storage"
	"github.com/spf13/viper"
	"golang.org/x/net/publicsuffix"
)

// Service defines Fetch service interface
type Service interface {
	Response(req FetchRequester) (FetchResponser, error)
	Fetch(req FetchRequester) (io.ReadCloser, error)
}

// FetchService implements service with empty struct
type FetchService struct {
}

// ServiceMiddleware defines a middleware for a Fetch service
type ServiceMiddleware func(Service) Service

//Response returns splash.Response
func (fs FetchService) Response(req FetchRequester) (FetchResponser, error) {

	var err error
	var fetcher Fetcher
	switch req.(type) {
	case BaseFetcherRequest:
		fetcher, err = NewFetcher(Base)
	case splash.Request:
		fetcher, err = NewFetcher(Splash)
	default:
		panic("invalid fetcher request")
	}

	if err != nil {
		logger.Error(err)
	}
	var (
		jar     *cookiejar.Jar
		cookies []byte
		cArr    []*http.Cookie
		s       storage.Store
	)
	if req.GetUserToken() != "" {
		storageType, err = storage.TypeString(viper.GetString("STORAGE_TYPE"))
		if err != nil {
			return nil, err
		}
		s = storage.NewStore(storageType)
		cookies, _ = s.Read(req.GetUserToken())
		jarOpts := &cookiejar.Options{PublicSuffixList: publicsuffix.List}
		jar, err = cookiejar.New(jarOpts)
		if err != nil {
			logger.Error("Failed to create Cookie Jar")

		}
		cArr = []*http.Cookie{}
		if len(cookies) != 0 {
			err = json.Unmarshal(cookies, &cArr)
			if err != nil {
				return nil, err
			}
			u, err := url.Parse(req.GetURL())
			if err != nil {
				return nil, err
			}
			tempCarr := []*http.Cookie{}
			for i := 0; i < len(cArr); i++ {
				c := cArr[i]
				if u.Host == c.Domain {
					tempCarr = append(tempCarr, c)
					cArr = append(cArr[:i], cArr[i+1:]...)
					i--
				}
			}
			jar.SetCookies(u, tempCarr)
		}
		fetcher.SetCookieJar(jar)
	}
	//res, err := fetcher.Fetch(req)
	res, err := fetcher.Response(req)
	if err != nil {
		return nil, err
	}
	if req.GetUserToken() != "" {
		jar = fetcher.GetCookieJar()
		cArr = append(cArr, jar.AllCookies()...)
		cookies, err = json.Marshal(cArr)
		logger.Info(string(cookies))
		if err != nil {
			return nil, err
		}
		err = s.Write(req.GetUserToken(), cookies, 0)
		if err != nil {
			return nil, err
		}
	}
	return res, nil
}

//Fetch downloads web page content and returns it
func (fs FetchService) Fetch(req FetchRequester) (io.ReadCloser, error) {
	res, err := fs.Response(req)
	if err != nil {
		return nil, err
	}
	return res.GetHTML()
}
<|endoftext|>


<commit_before>//Package filesystem provides a filesystem cache implementation for onecache
package filesystem

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/adelowo/onecache"
)

const (
	defaultFilePerm          os.FileMode = 0666
	defaultDirectoryFilePerm             = 0755
)

func createDirectory(dir string) error {

	return os.MkdirAll(dir, defaultDirectoryFilePerm)
}

type FSStore struct {
	baseDir string
}

//Returns an initialized Filesystem Cache
//If a non-existent directory is passed, it would be created automatically.
//This function Panics if the directory could not be created
func MustNewFSStore(baseDir string) *FSStore {

	_, err := os.Stat(baseDir)

	if err != nil { //Directory does not exist..Let's create it
		if err := createDirectory(baseDir); err != nil {
			panic(fmt.Errorf("Base directory could not be created : %s", err))
		}
	}

	return &FSStore{baseDir}
}

func (fs *FSStore) Set(key string, data interface{}, expiresAt time.Duration) error {

	path := fs.getFilePathFor(key)

	if err := os.MkdirAll(filepath.Dir(path), defaultDirectoryFilePerm); err != nil {
		return err
	}

	i := &onecache.Item{ExpiresAt: time.Now().Add(expiresAt), Data: data}

	b, err := i.Bytes()

	if err != nil {
		return err
	}

	if err = ioutil.WriteFile(path, b, defaultFilePerm); err != nil {
		return err
	}

	return nil
}

//Fetches a cache key.
//This runs garbage collection on the key if necessary
func (fs *FSStore) Get(key string) (interface{}, error) {

	b, err := ioutil.ReadFile(fs.getFilePathFor(key))

	if err != nil {
		return nil, err
	}

	i, err := onecache.BytesToItem(b)

	if i.IsExpired() {
		fs.Delete(key)
		return nil, onecache.ErrCacheMiss
	}

	return i.Data, nil
}

//Removes a file (cached item) from the disk
func (fs *FSStore) Delete(key string) error {
	return os.RemoveAll(fs.getFilePathFor(key))
}

//Cleans up the entire cache
func (fs *FSStore) Flush() error {
	return os.RemoveAll(fs.baseDir)
}

//Gets a unique path for a cache key.
//This is going to be a directory 3 level deep. Something like "basedir/33/rr/33/hash"
func (fs *FSStore) getFilePathFor(key string) string {
	hashSum := md5.Sum([]byte(key))

	hashSumAsString := hex.EncodeToString(hashSum[:])

	return filepath.Join(fs.baseDir,
		string(hashSumAsString[0:2]),
		string(hashSumAsString[2:4]),
		string(hashSumAsString[4:6]), hashSumAsString)
}
<commit_msg>Refactored method name<commit_after>//Package filesystem provides a filesystem cache implementation for onecache
package filesystem

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/adelowo/onecache"
)

const (
	defaultFilePerm          os.FileMode = 0666
	defaultDirectoryFilePerm             = 0755
)

func createDirectory(dir string) error {

	return os.MkdirAll(dir, defaultDirectoryFilePerm)
}

type FSStore struct {
	baseDir string
}

//Returns an initialized Filesystem Cache
//If a non-existent directory is passed, it would be created automatically.
//This function Panics if the directory could not be created
func MustNewFSStore(baseDir string) *FSStore {

	_, err := os.Stat(baseDir)

	if err != nil { //Directory does not exist..Let's create it
		if err := createDirectory(baseDir); err != nil {
			panic(fmt.Errorf("Base directory could not be created : %s", err))
		}
	}

	return &FSStore{baseDir}
}

func (fs *FSStore) Set(key string, data interface{}, expiresAt time.Duration) error {

	path := fs.filePathFor(key)

	if err := os.MkdirAll(filepath.Dir(path), defaultDirectoryFilePerm); err != nil {
		return err
	}

	i := &onecache.Item{ExpiresAt: time.Now().Add(expiresAt), Data: data}

	b, err := i.Bytes()

	if err != nil {
		return err
	}

	if err = ioutil.WriteFile(path, b, defaultFilePerm); err != nil {
		return err
	}

	return nil
}

//Fetches a cache key.
//This runs garbage collection on the key if necessary
func (fs *FSStore) Get(key string) (interface{}, error) {

	b, err := ioutil.ReadFile(fs.filePathFor(key))

	if err != nil {
		return nil, err
	}

	i, err := onecache.BytesToItem(b)

	if i.IsExpired() {
		fs.Delete(key)
		return nil, onecache.ErrCacheMiss
	}

	return i.Data, nil
}

//Removes a file (cached item) from the disk
func (fs *FSStore) Delete(key string) error {
	return os.RemoveAll(fs.filePathFor(key))
}

//Cleans up the entire cache
func (fs *FSStore) Flush() error {
	return os.RemoveAll(fs.baseDir)
}

//Gets a unique path for a cache key.
//This is going to be a directory 3 level deep. Something like "basedir/33/rr/33/hash"
func (fs *FSStore) filePathFor(key string) string {
	hashSum := md5.Sum([]byte(key))

	hashSumAsString := hex.EncodeToString(hashSum[:])

	return filepath.Join(fs.baseDir,
		string(hashSumAsString[0:2]),
		string(hashSumAsString[2:4]),
		string(hashSumAsString[4:6]), hashSumAsString)
}
<|endoftext|>


<commit_before>// fsimpl contains helper functions for implementing a fs.FileSystem
package fsimpl

import (
	"bytes"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"io"
	"io/ioutil"
	"net/url"
	"path"
	"strings"
)

// RandomString returns a 120 bit randum number
// encoded as URL compatible base64 string with a length of 20 characters.
func RandomString() string {
	var data [15]byte
	s := data[:]
	_, err := rand.Read(s)
	if err != nil {
		panic(err)
	}
	return base64.RawURLEncoding.EncodeToString(s)
}

// Ext returns the extension of filePath including the point, or an empty string.
// Example: Ext("image.png") == ".png"
func Ext(filePath string) string {
	p := strings.LastIndexByte(filePath, '.')
	if p == -1 {
		return ""
	}
	return filePath[p:]
}

// TrimExt returns a filePath with a path where the extension is removed.
func TrimExt(filePath string) string {
	p := strings.LastIndexByte(filePath, '.')
	if p == -1 {
		return filePath
	}
	return filePath[:p]
}

// DirAndName is a generic helper for FileSystem.DirAndName implementations.
// path.Split or filepath.Split don't have the wanted behaviour when given a path ending in a separator.
// DirAndName returns the parent directory of filePath and the name with that directory of the last filePath element.
// If filePath is the root of the file systeme, then an empty string will be returned as name.
// If filePath does not contain a separator before the name part, then "." will be returned as dir.
func DirAndName(filePath string, volumeLen int, separator string) (dir, name string) {
	if filePath == "" {
		return "", ""
	}

	filePath = strings.TrimSuffix(filePath, separator)

	if filePath == "" {
		return separator, ""
	}

	pos := strings.LastIndex(filePath, separator)
	if pos == -1 {
		return ".", filePath
	} else if pos <= volumeLen {
		return filePath, ""
	}

	return filePath[:pos], filePath[pos+1:]
}

// MatchAnyPattern returns true if name matches any of patterns,
// or if len(patterns) == 0.
// The match per pattern is checked via path.Match.
// FileSystem implementations can use this function to implement
// FileSystem.MatchAnyPattern they use "/" as path separator.
func MatchAnyPattern(name string, patterns []string) (bool, error) {
	if len(patterns) == 0 {
		return true, nil
	}
	for _, pattern := range patterns {
		match, err := path.Match(pattern, name)
		if match || err != nil {
			return match, err
		}
	}
	return false, nil
}

// ReadonlyFileBuffer is a memory buffer that implements ReadSeekCloser which combines the interfaces
// io.Reader
// io.ReaderAt
// io.Seeker
// io.Closer
type ReadonlyFileBuffer struct {
	data  []byte
	pos   int64
	close func() error
}

// NewReadonlyFileBuffer returns a new ReadonlyFileBuffer
func NewReadonlyFileBuffer(data []byte) *ReadonlyFileBuffer {
	return &ReadonlyFileBuffer{data: data}
}

func NewReadonlyFileBufferReadAll(reader io.Reader) (*ReadonlyFileBuffer, error) {
	data, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}
	return NewReadonlyFileBuffer(data), nil
}

// NewReadonlyFileBufferWithClose returns a new ReadonlyFileBuffer
func NewReadonlyFileBufferWithClose(data []byte, close func() error) *ReadonlyFileBuffer {
	return &ReadonlyFileBuffer{data: data, close: close}
}

// Bytes returns the bytes of the buffer.
func (buf *ReadonlyFileBuffer) Bytes() []byte {
	return buf.data
}

// Size returns the size of buffered file in bytes.
func (buf *ReadonlyFileBuffer) Size() int64 {
	return int64(len(buf.data))
}

// Read reads up to len(p) bytes into p. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered. Even if Read
// returns n < len(p), it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
// returns what is available instead of waiting for more.
func (buf *ReadonlyFileBuffer) Read(p []byte) (n int, err error) {
	n, err = buf.ReadAt(p, buf.pos)
	buf.pos += int64(n)
	return n, err
}

// ReadAt reads len(p) bytes into p starting at offset off in the
// underlying input source. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
func (buf *ReadonlyFileBuffer) ReadAt(p []byte, off int64) (n int, err error) {
	pos := int(off)
	if pos >= len(buf.data) {
		return 0, io.ErrShortBuffer
	}
	return copy(p, buf.data[pos:]), nil
}

// Seek sets the offset for the next Read or Write to offset,
// interpreted according to whence:
// SeekStart means relative to the start of the file,
// SeekCurrent means relative to the current offset, and
// SeekEnd means relative to the end.
// Seek returns the new offset relative to the start of the
// file and an error, if any.
//
// Seeking to an offset before the start of the file is an error.
// Seeking to any positive offset is legal, but the behavior of subsequent
// I/O operations on the underlying object is implementation-dependent.
func (buf *ReadonlyFileBuffer) Seek(offset int64, whence int) (newPos int64, err error) {
	switch whence {
	case io.SeekStart:
		newPos = offset
	case io.SeekCurrent:
		newPos = buf.pos + offset
	case io.SeekEnd:
		newPos = buf.Size() + offset
	default:
		return buf.pos, errors.New("Seek: invalid whence")
	}
	if newPos < 0 {
		return buf.pos, errors.New("Seek: negative position")
	}
	buf.pos = newPos
	return newPos, nil
}

// Close will free the internal buffer
func (buf *ReadonlyFileBuffer) Close() (err error) {
	if buf.close != nil {
		err = buf.close()
	}
	buf.data = nil
	buf.pos = 0
	buf.close = nil
	return err
}

// FileBuffer is a memory buffer that implements ReadWriteSeekCloser which combines the interfaces
// io.Reader
// io.ReaderAt
// io.Writer
// io.WriterAt
// io.Seeker
// io.Closer
type FileBuffer struct {
	ReadonlyFileBuffer
}

// NewFileBuffer returns a new FileBuffer
func NewFileBuffer(data []byte) *FileBuffer {
	return &FileBuffer{ReadonlyFileBuffer: ReadonlyFileBuffer{data: data}}
}

// NewFileBufferWithClose returns a new FileBuffer
func NewFileBufferWithClose(data []byte, close func() error) *FileBuffer {
	return &FileBuffer{ReadonlyFileBuffer: ReadonlyFileBuffer{data: data, close: close}}
}

// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
func (buf *ReadonlyFileBuffer) Write(p []byte) (n int, err error) {
	n, err = buf.WriteAt(p, buf.pos)
	buf.pos += int64(n)
	return n, err
}

// WriteAt writes len(p) bytes from p to the underlying data stream
// at offset off. It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// WriteAt must return a non-nil error if it returns n < len(p).
func (buf *ReadonlyFileBuffer) WriteAt(p []byte, off int64) (n int, err error) {
	numBytes := len(p)
	pos := int(buf.pos)
	writeEnd := pos + numBytes
	if writeEnd > len(buf.data) {
		newData := make([]byte, writeEnd)
		copy(newData, buf.data)
		buf.data = newData
	}
	return copy(buf.data[pos:], p), nil
}

const hashBlockSize = 4 * 1024 * 1024

// DropboxContentHash returns a Dropbox compatible content hash by reading from an io.Reader until io.EOF.
// See https://www.dropbox.com/developers/reference/content-hash
func DropboxContentHash(reader io.Reader) (string, error) {
	buf := make([]byte, hashBlockSize)
	resultHash := sha256.New()
	n, err := reader.Read(buf)
	if err != nil && err != io.EOF {
		return "", err
	}
	if n > 0 {
		bufHash := sha256.Sum256(buf[:n])
		resultHash.Write(bufHash[:])
	}
	for n == hashBlockSize && err == nil {
		n, err = reader.Read(buf)
		if err != nil && err != io.EOF {
			return "", err
		}
		if n > 0 {
			bufHash := sha256.Sum256(buf[:n])
			resultHash.Write(bufHash[:])
		}
	}
	return hex.EncodeToString(resultHash.Sum(nil)), nil
}

type ContentHasher interface {
	Hash(reader io.Reader) (string, error)
}

type ContentHasherFunc func(reader io.Reader) (string, error)

func (f ContentHasherFunc) Hash(reader io.Reader) (string, error) {
	return f(reader)
}

var ContentHash = ContentHasherFunc(DropboxContentHash)

// ContentHashBytes returns a Dropbox compatible content hash for a byte slice.
// See https://www.dropbox.com/developers/reference/content-hash
func ContentHashBytes(buf []byte) string {
	// bytes.Reader.Read only ever returns io.EOF
	// which is not treatet as error by ContentHash
	// so we can ignore all returned errors
	hash, _ := ContentHash(bytes.NewReader(buf))
	return hash
}

func JoinCleanPath(uriParts []string, prefix, separator string) string {
	if len(uriParts) > 0 {
		uriParts[0] = strings.TrimPrefix(uriParts[0], prefix)
	}
	cleanPath := path.Join(uriParts...)
	unescPath, err := url.PathUnescape(cleanPath)
	if err == nil {
		cleanPath = unescPath
	}
	if !strings.HasPrefix(cleanPath, separator) {
		cleanPath = separator + cleanPath
	}
	return path.Clean(cleanPath)
}

func SplitPath(filePath, prefix, separator string) []string {
	filePath = strings.TrimPrefix(filePath, prefix)
	filePath = strings.TrimPrefix(filePath, separator)
	filePath = strings.TrimSuffix(filePath, separator)
	return strings.Split(filePath, separator)
}
<commit_msg>var naming<commit_after>// fsimpl contains helper functions for implementing a fs.FileSystem
package fsimpl

import (
	"bytes"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"io"
	"io/ioutil"
	"net/url"
	"path"
	"strings"
)

// RandomString returns a 120 bit randum number
// encoded as URL compatible base64 string with a length of 20 characters.
func RandomString() string {
	var buffer [15]byte
	b := buffer[:]
	_, err := rand.Read(b)
	if err != nil {
		panic(err)
	}
	return base64.RawURLEncoding.EncodeToString(b)
}

// Ext returns the extension of filePath including the point, or an empty string.
// Example: Ext("image.png") == ".png"
func Ext(filePath string) string {
	p := strings.LastIndexByte(filePath, '.')
	if p == -1 {
		return ""
	}
	return filePath[p:]
}

// TrimExt returns a filePath with a path where the extension is removed.
func TrimExt(filePath string) string {
	p := strings.LastIndexByte(filePath, '.')
	if p == -1 {
		return filePath
	}
	return filePath[:p]
}

// DirAndName is a generic helper for FileSystem.DirAndName implementations.
// path.Split or filepath.Split don't have the wanted behaviour when given a path ending in a separator.
// DirAndName returns the parent directory of filePath and the name with that directory of the last filePath element.
// If filePath is the root of the file systeme, then an empty string will be returned as name.
// If filePath does not contain a separator before the name part, then "." will be returned as dir.
func DirAndName(filePath string, volumeLen int, separator string) (dir, name string) {
	if filePath == "" {
		return "", ""
	}

	filePath = strings.TrimSuffix(filePath, separator)

	if filePath == "" {
		return separator, ""
	}

	pos := strings.LastIndex(filePath, separator)
	if pos == -1 {
		return ".", filePath
	} else if pos <= volumeLen {
		return filePath, ""
	}

	return filePath[:pos], filePath[pos+1:]
}

// MatchAnyPattern returns true if name matches any of patterns,
// or if len(patterns) == 0.
// The match per pattern is checked via path.Match.
// FileSystem implementations can use this function to implement
// FileSystem.MatchAnyPattern they use "/" as path separator.
func MatchAnyPattern(name string, patterns []string) (bool, error) {
	if len(patterns) == 0 {
		return true, nil
	}
	for _, pattern := range patterns {
		match, err := path.Match(pattern, name)
		if match || err != nil {
			return match, err
		}
	}
	return false, nil
}

// ReadonlyFileBuffer is a memory buffer that implements ReadSeekCloser which combines the interfaces
// io.Reader
// io.ReaderAt
// io.Seeker
// io.Closer
type ReadonlyFileBuffer struct {
	data  []byte
	pos   int64
	close func() error
}

// NewReadonlyFileBuffer returns a new ReadonlyFileBuffer
func NewReadonlyFileBuffer(data []byte) *ReadonlyFileBuffer {
	return &ReadonlyFileBuffer{data: data}
}

func NewReadonlyFileBufferReadAll(reader io.Reader) (*ReadonlyFileBuffer, error) {
	data, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}
	return NewReadonlyFileBuffer(data), nil
}

// NewReadonlyFileBufferWithClose returns a new ReadonlyFileBuffer
func NewReadonlyFileBufferWithClose(data []byte, close func() error) *ReadonlyFileBuffer {
	return &ReadonlyFileBuffer{data: data, close: close}
}

// Bytes returns the bytes of the buffer.
func (buf *ReadonlyFileBuffer) Bytes() []byte {
	return buf.data
}

// Size returns the size of buffered file in bytes.
func (buf *ReadonlyFileBuffer) Size() int64 {
	return int64(len(buf.data))
}

// Read reads up to len(p) bytes into p. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered. Even if Read
// returns n < len(p), it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
// returns what is available instead of waiting for more.
func (buf *ReadonlyFileBuffer) Read(p []byte) (n int, err error) {
	n, err = buf.ReadAt(p, buf.pos)
	buf.pos += int64(n)
	return n, err
}

// ReadAt reads len(p) bytes into p starting at offset off in the
// underlying input source. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
func (buf *ReadonlyFileBuffer) ReadAt(p []byte, off int64) (n int, err error) {
	pos := int(off)
	if pos >= len(buf.data) {
		return 0, io.ErrShortBuffer
	}
	return copy(p, buf.data[pos:]), nil
}

// Seek sets the offset for the next Read or Write to offset,
// interpreted according to whence:
// SeekStart means relative to the start of the file,
// SeekCurrent means relative to the current offset, and
// SeekEnd means relative to the end.
// Seek returns the new offset relative to the start of the
// file and an error, if any.
//
// Seeking to an offset before the start of the file is an error.
// Seeking to any positive offset is legal, but the behavior of subsequent
// I/O operations on the underlying object is implementation-dependent.
func (buf *ReadonlyFileBuffer) Seek(offset int64, whence int) (newPos int64, err error) {
	switch whence {
	case io.SeekStart:
		newPos = offset
	case io.SeekCurrent:
		newPos = buf.pos + offset
	case io.SeekEnd:
		newPos = buf.Size() + offset
	default:
		return buf.pos, errors.New("Seek: invalid whence")
	}
	if newPos < 0 {
		return buf.pos, errors.New("Seek: negative position")
	}
	buf.pos = newPos
	return newPos, nil
}

// Close will free the internal buffer
func (buf *ReadonlyFileBuffer) Close() (err error) {
	if buf.close != nil {
		err = buf.close()
	}
	buf.data = nil
	buf.pos = 0
	buf.close = nil
	return err
}

// FileBuffer is a memory buffer that implements ReadWriteSeekCloser which combines the interfaces
// io.Reader
// io.ReaderAt
// io.Writer
// io.WriterAt
// io.Seeker
// io.Closer
type FileBuffer struct {
	ReadonlyFileBuffer
}

// NewFileBuffer returns a new FileBuffer
func NewFileBuffer(data []byte) *FileBuffer {
	return &FileBuffer{ReadonlyFileBuffer: ReadonlyFileBuffer{data: data}}
}

// NewFileBufferWithClose returns a new FileBuffer
func NewFileBufferWithClose(data []byte, close func() error) *FileBuffer {
	return &FileBuffer{ReadonlyFileBuffer: ReadonlyFileBuffer{data: data, close: close}}
}

// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
func (buf *ReadonlyFileBuffer) Write(p []byte) (n int, err error) {
	n, err = buf.WriteAt(p, buf.pos)
	buf.pos += int64(n)
	return n, err
}

// WriteAt writes len(p) bytes from p to the underlying data stream
// at offset off. It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// WriteAt must return a non-nil error if it returns n < len(p).
func (buf *ReadonlyFileBuffer) WriteAt(p []byte, off int64) (n int, err error) {
	numBytes := len(p)
	pos := int(buf.pos)
	writeEnd := pos + numBytes
	if writeEnd > len(buf.data) {
		newData := make([]byte, writeEnd)
		copy(newData, buf.data)
		buf.data = newData
	}
	return copy(buf.data[pos:], p), nil
}

const hashBlockSize = 4 * 1024 * 1024

// DropboxContentHash returns a Dropbox compatible content hash by reading from an io.Reader until io.EOF.
// See https://www.dropbox.com/developers/reference/content-hash
func DropboxContentHash(reader io.Reader) (string, error) {
	buf := make([]byte, hashBlockSize)
	resultHash := sha256.New()
	n, err := reader.Read(buf)
	if err != nil && err != io.EOF {
		return "", err
	}
	if n > 0 {
		bufHash := sha256.Sum256(buf[:n])
		resultHash.Write(bufHash[:])
	}
	for n == hashBlockSize && err == nil {
		n, err = reader.Read(buf)
		if err != nil && err != io.EOF {
			return "", err
		}
		if n > 0 {
			bufHash := sha256.Sum256(buf[:n])
			resultHash.Write(bufHash[:])
		}
	}
	return hex.EncodeToString(resultHash.Sum(nil)), nil
}

type ContentHasher interface {
	Hash(reader io.Reader) (string, error)
}

type ContentHasherFunc func(reader io.Reader) (string, error)

func (f ContentHasherFunc) Hash(reader io.Reader) (string, error) {
	return f(reader)
}

var ContentHash = ContentHasherFunc(DropboxContentHash)

// ContentHashBytes returns a Dropbox compatible content hash for a byte slice.
// See https://www.dropbox.com/developers/reference/content-hash
func ContentHashBytes(buf []byte) string {
	// bytes.Reader.Read only ever returns io.EOF
	// which is not treatet as error by ContentHash
	// so we can ignore all returned errors
	hash, _ := ContentHash(bytes.NewReader(buf))
	return hash
}

func JoinCleanPath(uriParts []string, prefix, separator string) string {
	if len(uriParts) > 0 {
		uriParts[0] = strings.TrimPrefix(uriParts[0], prefix)
	}
	cleanPath := path.Join(uriParts...)
	unescPath, err := url.PathUnescape(cleanPath)
	if err == nil {
		cleanPath = unescPath
	}
	if !strings.HasPrefix(cleanPath, separator) {
		cleanPath = separator + cleanPath
	}
	return path.Clean(cleanPath)
}

func SplitPath(filePath, prefix, separator string) []string {
	filePath = strings.TrimPrefix(filePath, prefix)
	filePath = strings.TrimPrefix(filePath, separator)
	filePath = strings.TrimSuffix(filePath, separator)
	return strings.Split(filePath, separator)
}
<|endoftext|>