<commit_before>package provider

import (
	"crypto/rand"
	"errors"
	"github.com/GehirnInc/GOpenID"
	"strings"
	"time"
)

var (
	ErrAlreadySigned      = errors.New("response has been signed")
	ErrNotNeedsSigning    = errors.New("response does not need signing")
	ErrIdentityNotSet     = errors.New("identity not set")
	ErrIdentitySet        = errors.New("identity set")
	ErrIdentityNotMatched = errors.New("identity not matched")
	ErrMessageNotSigned   = errors.New("message is not signed")
)

type Signer struct {
	store    gopenid.AssociationStore
	lifetime int64
}

func (s *Signer) Invalidate(handle string, isStateless bool) (err error) {
	assoc, err := s.store.GetAssociation(handle, isStateless)
	if err != nil {
		return
	}

	err = s.store.DeleteAssociation(assoc)
	return
}

func (s *Signer) Verify(req Request, isStateless bool) (ok bool, err error) {
	msg := req.GetMessage()
	verify := msg.Copy()

	assocHandle, ok := msg.GetArg(
		gopenid.NewMessageKey(msg.GetOpenIDNamespace(), "assoc_handle"),
	)
	if !ok {
		err = ErrMessageNotSigned
		return
	}

	_order, ok := msg.GetArg(
		gopenid.NewMessageKey(msg.GetOpenIDNamespace(), "signed"),
	)
	if !ok {
		err = ErrMessageNotSigned
		return
	}
	order := strings.Split(_order.String(), ",")

	sig, ok := msg.GetArg(
		gopenid.NewMessageKey(msg.GetOpenIDNamespace(), "sig"),
	)
	if !ok {
		err = ErrMessageNotSigned
		return
	}

	assoc, err := s.store.GetAssociation(assocHandle.String(), isStateless)
	if err != nil {
		return
	}

	err = assoc.Sign(verify, order)
	if err != nil {
		return
	}
	expected, _ := msg.GetArg(gopenid.NewMessageKey(verify.GetOpenIDNamespace(), "sig"))

	ok = sig == expected
	return
}

func (s *Signer) Sign(res *Response, assocHandle string) (err error) {
	assoc, err := s.getAssociation(assocHandle)
	if err != nil {
		return
	}

	order := []string{
		"op_endpoint",
		"return_to",
		"response_nonce",
		"assoc_handle",
		"claimed_id",
		"identity",
	}

	if _, ok := res.message.GetArg(gopenid.NewMessageKey(res.message.GetOpenIDNamespace(), "identity")); !ok {
		order = order[:5]
	}

	if _, ok := res.message.GetArg(gopenid.NewMessageKey(res.message.GetOpenIDNamespace(), "claimed_id")); !ok {
		copy(order[4:], order[len(order)-1:])
		order = order[:len(order)-1]
	}

	return assoc.Sign(res.message, order)
}

func (s *Signer) getExpires() int64 {
	return time.Now().Unix() + s.lifetime
}

func (s *Signer) getAssociation(assocHandle string) (assoc *gopenid.Association, err error) {
	var (
		DEFAULT_ASSOC_TYPE = gopenid.ASSOC_HMAC_SHA1
	)

	if assocHandle == "" {
		assoc, err = gopenid.CreateAssociation(
			rand.Reader,
			DEFAULT_ASSOC_TYPE,
			s.getExpires(),
			true,
		)
	} else {
		assoc, err = s.store.GetAssociation(assocHandle, false)
		if err == nil {
			if !assoc.IsValid() {
				assoc, err = gopenid.CreateAssociation(
					rand.Reader,
					assoc.GetAssocType(),
					s.getExpires(),
					true,
				)
			}
		} else if err == gopenid.ErrAssociationNotFound {
			assoc, err = gopenid.CreateAssociation(
				rand.Reader,
				DEFAULT_ASSOC_TYPE,
				s.getExpires(),
				true,
			)
		} else {
			return
		}
	}

	if err != nil {
		return
	}

	if assoc.IsStateless() {
		err = s.store.StoreAssociation(assoc)
		if err != nil {
			return
		}
	}

	return
}
<commit_msg>add NewSigner<commit_after>package provider

import (
	"crypto/rand"
	"errors"
	"github.com/GehirnInc/GOpenID"
	"strings"
	"time"
)

var (
	ErrAlreadySigned      = errors.New("response has been signed")
	ErrNotNeedsSigning    = errors.New("response does not need signing")
	ErrIdentityNotSet     = errors.New("identity not set")
	ErrIdentitySet        = errors.New("identity set")
	ErrIdentityNotMatched = errors.New("identity not matched")
	ErrMessageNotSigned   = errors.New("message is not signed")
)

type Signer struct {
	store    gopenid.AssociationStore
	lifetime int64
}

func NewSigner(store gopenid.AssociationStore, lifetime int64) *Signer {
	return &Signer{
		store:    store,
		lifetime: lifetime,
	}
}

func (s *Signer) Invalidate(handle string, isStateless bool) (err error) {
	assoc, err := s.store.GetAssociation(handle, isStateless)
	if err != nil {
		return
	}

	err = s.store.DeleteAssociation(assoc)
	return
}

func (s *Signer) Verify(req Request, isStateless bool) (ok bool, err error) {
	msg := req.GetMessage()
	verify := msg.Copy()

	assocHandle, ok := msg.GetArg(
		gopenid.NewMessageKey(msg.GetOpenIDNamespace(), "assoc_handle"),
	)
	if !ok {
		err = ErrMessageNotSigned
		return
	}

	_order, ok := msg.GetArg(
		gopenid.NewMessageKey(msg.GetOpenIDNamespace(), "signed"),
	)
	if !ok {
		err = ErrMessageNotSigned
		return
	}
	order := strings.Split(_order.String(), ",")

	sig, ok := msg.GetArg(
		gopenid.NewMessageKey(msg.GetOpenIDNamespace(), "sig"),
	)
	if !ok {
		err = ErrMessageNotSigned
		return
	}

	assoc, err := s.store.GetAssociation(assocHandle.String(), isStateless)
	if err != nil {
		return
	}

	err = assoc.Sign(verify, order)
	if err != nil {
		return
	}
	expected, _ := msg.GetArg(gopenid.NewMessageKey(verify.GetOpenIDNamespace(), "sig"))

	ok = sig == expected
	return
}

func (s *Signer) Sign(res *Response, assocHandle string) (err error) {
	assoc, err := s.getAssociation(assocHandle)
	if err != nil {
		return
	}

	order := []string{
		"op_endpoint",
		"return_to",
		"response_nonce",
		"assoc_handle",
		"claimed_id",
		"identity",
	}

	if _, ok := res.message.GetArg(gopenid.NewMessageKey(res.message.GetOpenIDNamespace(), "identity")); !ok {
		order = order[:5]
	}

	if _, ok := res.message.GetArg(gopenid.NewMessageKey(res.message.GetOpenIDNamespace(), "claimed_id")); !ok {
		copy(order[4:], order[len(order)-1:])
		order = order[:len(order)-1]
	}

	return assoc.Sign(res.message, order)
}

func (s *Signer) getExpires() int64 {
	return time.Now().Unix() + s.lifetime
}

func (s *Signer) getAssociation(assocHandle string) (assoc *gopenid.Association, err error) {
	var (
		DEFAULT_ASSOC_TYPE = gopenid.ASSOC_HMAC_SHA1
	)

	if assocHandle == "" {
		assoc, err = gopenid.CreateAssociation(
			rand.Reader,
			DEFAULT_ASSOC_TYPE,
			s.getExpires(),
			true,
		)
	} else {
		assoc, err = s.store.GetAssociation(assocHandle, false)
		if err == nil {
			if !assoc.IsValid() {
				assoc, err = gopenid.CreateAssociation(
					rand.Reader,
					assoc.GetAssocType(),
					s.getExpires(),
					true,
				)
			}
		} else if err == gopenid.ErrAssociationNotFound {
			assoc, err = gopenid.CreateAssociation(
				rand.Reader,
				DEFAULT_ASSOC_TYPE,
				s.getExpires(),
				true,
			)
		} else {
			return
		}
	}

	if err != nil {
		return
	}

	if assoc.IsStateless() {
		err = s.store.StoreAssociation(assoc)
		if err != nil {
			return
		}
	}

	return
}
<|endoftext|>


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

package builder

import (
	"bytes"
	"io"
)

// Writer defines the interface
type Writer interface {
	io.Writer
	Append(...interface{})
}

var _ Writer = NewWriter()

// BytesWriter implments Writer and save SQL in bytes.Buffer
type BytesWriter struct {
	writer *bytes.Buffer
	buffer []byte
	args   []interface{}
}

// NewWriter creates a new string writer
func NewWriter() *BytesWriter {
	w := &BytesWriter{}
	w.writer = bytes.NewBuffer(w.buffer)
	return w
}

// Write writes data to Writer
func (s *BytesWriter) Write(buf []byte) (int, error) {
	return s.writer.Write(buf)
}

// Append appends args to Writer
func (s *BytesWriter) Append(args ...interface{}) {
	s.args = append(s.args, args...)
}

// Cond defines an interface
type Cond interface {
	WriteTo(Writer) error
	And(...Cond) Cond
	Or(...Cond) Cond
	IsValid() bool
}

type condEmpty struct{}

var _ Cond = condEmpty{}

// NewCond creates an empty condition
func NewCond() Cond {
	return condEmpty{}
}

func (condEmpty) WriteTo(w Writer) error {
	return nil
}

func (condEmpty) And(conds ...Cond) Cond {
	return And(conds...)
}

func (condEmpty) Or(conds ...Cond) Cond {
	return Or(conds...)
}

func (condEmpty) IsValid() bool {
	return false
}

func condToSQL(cond Cond) (string, []interface{}, error) {
	if cond == nil || !cond.IsValid() {
		return "", nil, nil
	}

	w := NewWriter()
	if err := cond.WriteTo(w); err != nil {
		return "", nil, err
	}
	return w.writer.String(), w.args, nil
}
<commit_msg>upadate<commit_after>// Copyright 2016 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package builder

import (
	"bytes"
	"io"
)

// Writer defines the interface
type Writer interface {
	io.Writer
	Append(...interface{})
}

var _ Writer = NewWriter()

// BytesWriter implments Writer and save SQL in bytes.Buffer
type BytesWriter struct {
	writer *bytes.Buffer
	buffer []byte
	args   []interface{}
}

// NewWriter creates a new string writer
func NewWriter() *BytesWriter {
	w := &BytesWriter{}
	w.writer = bytes.NewBuffer(w.buffer)
	return w
}

// Write writes data to Writer
func (s *BytesWriter) Write(buf []byte) (int, error) {
	return s.writer.Write(buf)
}

// Append appends args to Writer
func (s *BytesWriter) Append(args ...interface{}) {
	s.args = append(s.args, args...)
}

func (s *BytesWriter) String() string {
	return s.writer.String()
}

func (s *BytesWriter) Bytes() []byte {
	return s.writer.Bytes()
}

// Cond defines an interface
type Cond interface {
	WriteTo(Writer) error
	And(...Cond) Cond
	Or(...Cond) Cond
	IsValid() bool
}

type condEmpty struct{}

var _ Cond = condEmpty{}

// NewCond creates an empty condition
func NewCond() Cond {
	return condEmpty{}
}

func (condEmpty) WriteTo(w Writer) error {
	return nil
}

func (condEmpty) And(conds ...Cond) Cond {
	return And(conds...)
}

func (condEmpty) Or(conds ...Cond) Cond {
	return Or(conds...)
}

func (condEmpty) IsValid() bool {
	return false
}

func condToSQL(cond Cond) (string, []interface{}, error) {
	if cond == nil || !cond.IsValid() {
		return "", nil, nil
	}

	w := NewWriter()
	if err := cond.WriteTo(w); err != nil {
		return "", nil, err
	}
	return w.writer.String(), w.args, nil
}
<|endoftext|>


<commit_before>// Copyright 2013 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 transform handles image transformation such as resizing.
package proxy

import (
	"bytes"
	"image"
	"image/gif"
	"image/jpeg"
	"image/png"
	"reflect"

	"github.com/disintegration/imaging"
)

// Transform the provided image.
func Transform(img []byte, opt *Options) ([]byte, error) {
	if opt == nil || reflect.DeepEqual(opt, emptyOptions) {
		// bail if no transformation was requested
		return img, nil
	}

	// decode image
	m, format, err := image.Decode(bytes.NewReader(img))
	if err != nil {
		return nil, err
	}

	// convert percentage width and height values to absolute values
	var h, w int
	if opt.Width > 0 && opt.Width < 1 {
		w = int(float64(m.Bounds().Max.X-m.Bounds().Min.X) * opt.Width)
	} else {
		w = int(opt.Width)
	}
	if opt.Height > 0 && opt.Height < 1 {
		h = int(float64(m.Bounds().Max.Y-m.Bounds().Min.Y) * opt.Height)
	} else {
		h = int(opt.Height)
	}

	// resize
	if w != 0 || h != 0 {
		if opt.Fit {
			m = imaging.Fit(m, w, h, imaging.Lanczos)
		} else {
			if w == 0 || h == 0 {
				m = imaging.Resize(m, w, h, imaging.Lanczos)
			} else {
				m = imaging.Thumbnail(m, w, h, imaging.Lanczos)
			}
		}
	}

	// flip
	if opt.FlipVertical {
		m = imaging.FlipV(m)
	}
	if opt.FlipHorizontal {
		m = imaging.FlipH(m)
	}

	// rotate
	switch opt.Rotate {
	case 90:
		m = imaging.Rotate90(m)
		break
	case 180:
		m = imaging.Rotate180(m)
		break
	case 270:
		m = imaging.Rotate270(m)
		break
	}

	// encode image
	buf := new(bytes.Buffer)
	switch format {
	case "gif":
		gif.Encode(buf, m, nil)
		break
	case "jpeg":
		jpeg.Encode(buf, m, nil)
		break
	case "png":
		png.Encode(buf, m)
		break
	}

	return buf.Bytes(), nil
}
<commit_msg>never resize larger than the original image<commit_after>// Copyright 2013 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 transform handles image transformation such as resizing.
package proxy

import (
	"bytes"
	"image"
	"image/gif"
	"image/jpeg"
	"image/png"
	"reflect"

	"github.com/disintegration/imaging"
)

// Transform the provided image.
func Transform(img []byte, opt *Options) ([]byte, error) {
	if opt == nil || reflect.DeepEqual(opt, emptyOptions) {
		// bail if no transformation was requested
		return img, nil
	}

	// decode image
	m, format, err := image.Decode(bytes.NewReader(img))
	if err != nil {
		return nil, err
	}

	// convert percentage width and height values to absolute values
	imgW := m.Bounds().Max.X - m.Bounds().Min.X
	imgH := m.Bounds().Max.Y - m.Bounds().Min.Y
	var h, w int
	if opt.Width > 0 && opt.Width < 1 {
		w = int(float64(imgW) * opt.Width)
	} else {
		w = int(opt.Width)
	}
	if opt.Height > 0 && opt.Height < 1 {
		h = int(float64(imgH) * opt.Height)
	} else {
		h = int(opt.Height)
	}

	// never resize larger than the original image
	if w > imgW {
		w = imgW
	}
	if h > imgH {
		h = imgH
	}

	// resize
	if w != 0 || h != 0 {
		if opt.Fit {
			m = imaging.Fit(m, w, h, imaging.Lanczos)
		} else {
			if w == 0 || h == 0 {
				m = imaging.Resize(m, w, h, imaging.Lanczos)
			} else {
				m = imaging.Thumbnail(m, w, h, imaging.Lanczos)
			}
		}
	}

	// flip
	if opt.FlipVertical {
		m = imaging.FlipV(m)
	}
	if opt.FlipHorizontal {
		m = imaging.FlipH(m)
	}

	// rotate
	switch opt.Rotate {
	case 90:
		m = imaging.Rotate90(m)
		break
	case 180:
		m = imaging.Rotate180(m)
		break
	case 270:
		m = imaging.Rotate270(m)
		break
	}

	// encode image
	buf := new(bytes.Buffer)
	switch format {
	case "gif":
		gif.Encode(buf, m, nil)
		break
	case "jpeg":
		jpeg.Encode(buf, m, nil)
		break
	case "png":
		png.Encode(buf, m)
		break
	}

	return buf.Bytes(), nil
}
<|endoftext|>


<commit_before>package jo

// Parsing events.
type Event int

const (
	None = iota
	SyntaxError

	StringStart
	StringEnd
	NumberStart
	NumberEnd
	BoolStart
	BoolEnd
	NullStart
	NullEnd
)

// Parser states.
const (
	_StateValue = iota

	_StateStringUnicode  // "\u
	_StateStringUnicode2 // "\u1
	_StateStringUnicode3 // "\u12
	_StateStringUnicode4 // "\u123
	_StateString         // "
	_StateStringEscaped  // "\

	_StateNumberNegative           // -
	_StateNumberZero               // 0
	_StateNumber                   // 123
	_StateNumberDotFirstDigit      // 123.
	_StateNumberDotDigit           // 123.4
	_StateNumberExponentSign       // 123e
	_StateNumberExponentFirstDigit // 123e+
	_StateNumberExponentDigit      // 123e+1

	_StateTrue  // t
	_StateTrue2 // tr
	_StateTrue3 // tru

	_StateFalse  // f
	_StateFalse2 // fa
	_StateFalse3 // fal
	_StateFalse4 // fals

	_StateNull  // n
	_StateNull2 // nu
	_StateNull3 // nul

	_StateDone
	_StateSyntaxError
)

// Our own little implementation of the `error` interface.
type syntaxError string

func (e syntaxError) Error() string {
	return string(e)
}

// Parser state machine.
type Parser struct {
	state int
	queue []int
	err   error
}

// Parses a byte slice containing JSON data. Returns the number of bytes
// read and an appropriate Event.
func (p *Parser) Parse(input []byte) (int, Event) {
	for i, b := range input {
		switch p.state {
		case _StateValue:
			switch {
			case b == '"':
				p.state = _StateString
				return i + 1, StringStart
			case b == '-':
				p.state = _StateNumberNegative
				return i + 1, NumberStart
			case b == '0':
				p.state = _StateNumberZero
				return i + 1, NumberStart
			case '1' <= b && b <= '9':
				p.state = _StateNumber
				return i + 1, NumberStart
			case b == 't':
				p.state = _StateTrue
				return i + 1, BoolStart
			case b == 'f':
				p.state = _StateFalse
				return i + 1, BoolStart
			case b == 'n':
				p.state = _StateNull
				return i + 1, NullStart
			default:
				return i, p.error(`_StateValue: @todo`)
			}

		case _StateStringUnicode, _StateStringUnicode2,
			_StateStringUnicode3, _StateStringUnicode4:
			switch {
			case '0' <= b && b <= '9':
			case 'a' <= b && b <= 'f':
			case 'A' <= b && b <= 'F':
			default:
				return i, p.error(`_StateStringUnicodeX: @todo`)
			}

			p.state++ // note that `_StateString == (_StateStringUnicode4 + 1)`

		case _StateString:
			switch {
			case b == '"':
				p.state = p.next()
				return i + 1, StringEnd
			case b == '\\':
				p.state = _StateStringEscaped
			case b < 0x20:
				return i, p.error(`_StateString: @todo`)
			}

		case _StateStringEscaped:
			switch b {
			case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
				p.state = _StateString
			case 'u':
				p.state = _StateStringUnicode
			default:
				return i, p.error(`_StateStringEscaped: @todo`)
			}

		case _StateNumberNegative:
			switch {
			case b == '0':
				p.state = _StateNumberZero
			case '1' <= b && b <= '9':
				p.state = _StateNumber
			default:
				return i, p.error(`_StateNumberNegative: @todo`)
			}

		case _StateNumber:
			if '0' <= b && b <= '9' {
				break
			}
			fallthrough

		case _StateNumberZero:
			switch b {
			case '.':
				p.state = _StateNumberDotFirstDigit
			case 'e', 'E':
				p.state = _StateNumberExponentSign
			default:
				return i, p.error(`_StateNumberZero: @todo`)
			}

		case _StateNumberDotFirstDigit:
			if b < '0' || b > '9' {
				return i, p.error(`_StateNumberDot: @todo`)
			}
			p.state++

		case _StateNumberDotDigit:
			switch {
			case b == 'e', b == 'E':
				p.state = _StateNumberExponentSign
			case b < '0' || b > '9':
				return i, p.error(`_StateNumberDotDigit: @todo`)
			}

		case _StateNumberExponentSign:
			p.state++
			if b == '+' || b == '-' {
				break
			}
			fallthrough

		case _StateNumberExponentFirstDigit:
			if b < '0' || b > '9' {
				return i, p.error(`_StateNumberAfterExponent: @todo`)
			}
			p.state++

		case _StateNumberExponentDigit:
			if b < '0' || b > '9' {
				p.state = p.next()
				return i + 1, NumberEnd
			}

		case _StateTrue:
			if b != 'r' {
				return i, p.error(`_StateTrue: @todo`)
			}
			p.state++

		case _StateTrue2:
			if b != 'u' {
				return i, p.error(`_StateTrue2: @todo`)
			}
			p.state++

		case _StateTrue3:
			if b != 'e' {
				return i, p.error(`_StateTrue3: @todo`)
			}
			p.state = p.next()

			return i + 1, BoolEnd

		case _StateFalse:
			if b != 'a' {
				return i, p.error(`_StateFalse: @todo`)
			}
			p.state++

		case _StateFalse2:
			if b != 'l' {
				return i, p.error(`_StateFalse2: @todo`)
			}
			p.state++

		case _StateFalse3:
			if b != 's' {
				return i, p.error(`_StateFalse3: @todo`)
			}
			p.state++

		case _StateFalse4:
			if b != 'e' {
				return i, p.error(`_StateFalse4: @todo`)
			}
			p.state = p.next()

			return i + 1, BoolEnd

		case _StateNull:
			if b != 'u' {
				return i, p.error(`_StateNull: @todo`)
			}
			p.state++

		case _StateNull2:
			if b != 'l' {
				return i, p.error(`_StateNull2: @todo`)
			}
			p.state++

		case _StateNull3:
			if b != 'l' {
				return i, p.error(`_StateNull3: @todo`)
			}
			p.state = p.next()

			return i + 1, NullEnd

		case _StateDone:
			return i, p.error(`_StateDone: @todo`)

		default:
			panic(`invalid state`)
		}
	}

	return len(input), None
}

// Informs the parser not to expect any further input. Returns
// pending NumberEnd events if there are any, or a SyntaxError
// if EOF was not expected -- otherwise None.
func (p *Parser) Eof() Event {
	switch p.state {
	case _StateNumberZero,
		_StateNumber,
		_StateNumberDotDigit,
		_StateNumberExponentDigit:
		p.state = _StateDone
		return NumberEnd
	case _StateDone:
		return None
	}
	return p.error(`.Eof(): @todo`)
}

// Pops the next state off the parser struct's queue.
func (p *Parser) next() int {
	length := len(p.queue)

	// with the "state queue" empty, we can only wait for EOF
	if length == 0 {
		return _StateDone
	}

	state := p.queue[length]
	p.queue = p.queue[:length-1]

	return state
}

// Insert a new state at the top of the queue.
func (p *Parser) push(state int) {
	p.queue = append(p.queue, state)
}

// Registers a syntax error. Always returns a SyntaxError event.
func (p *Parser) error(message string) Event {
	p.err = syntaxError(message)
	return SyntaxError
}
<commit_msg>Add Array support<commit_after>package jo

// Parsing events.
type Event int

const (
	None = iota
	SyntaxError

	ArrayStart
	ArrayEnd

	StringStart
	StringEnd
	NumberStart
	NumberEnd
	BoolStart
	BoolEnd
	NullStart
	NullEnd
)

// Parser states.
const (
	_StateValue = iota

	_StateArrayValueOrEnd // [
	_StateArrayCommaOrEnd // ["any value"
	_StateArrayValue      // ["any value",

	_StateStringUnicode  // "\u
	_StateStringUnicode2 // "\u1
	_StateStringUnicode3 // "\u12
	_StateStringUnicode4 // "\u123
	_StateString         // "
	_StateStringEscaped  // "\

	_StateNumberNegative           // -
	_StateNumberZero               // 0
	_StateNumber                   // 123
	_StateNumberDotFirstDigit      // 123.
	_StateNumberDotDigit           // 123.4
	_StateNumberExponentSign       // 123e
	_StateNumberExponentFirstDigit // 123e+
	_StateNumberExponentDigit      // 123e+1

	_StateTrue  // t
	_StateTrue2 // tr
	_StateTrue3 // tru

	_StateFalse  // f
	_StateFalse2 // fa
	_StateFalse3 // fal
	_StateFalse4 // fals

	_StateNull  // n
	_StateNull2 // nu
	_StateNull3 // nul

	_StateDone
	_StateSyntaxError
)

// Our own little implementation of the `error` interface.
type syntaxError string

func (e syntaxError) Error() string {
	return string(e)
}

// Parser state machine.
type Parser struct {
	state int
	queue []int
	err   error
}

// Parses a byte slice containing JSON data. Returns the number of bytes
// read and an appropriate Event.
func (p *Parser) Parse(input []byte) (int, Event) {
	for i := 0; i < len(input); i++ {
		b := input[i]

		switch p.state {
		case _StateValue:
			switch {
			case b == '[':
				p.state = _StateArrayValueOrEnd
				return i + 1, ArrayStart
			case b == '"':
				p.state = _StateString
				return i + 1, StringStart
			case b == '-':
				p.state = _StateNumberNegative
				return i + 1, NumberStart
			case b == '0':
				p.state = _StateNumberZero
				return i + 1, NumberStart
			case '1' <= b && b <= '9':
				p.state = _StateNumber
				return i + 1, NumberStart
			case b == 't':
				p.state = _StateTrue
				return i + 1, BoolStart
			case b == 'f':
				p.state = _StateFalse
				return i + 1, BoolStart
			case b == 'n':
				p.state = _StateNull
				return i + 1, NullStart
			default:
				return i, p.error(`_StateValue: @todo`)
			}

		case _StateArrayValueOrEnd:
			if b == ']' {
				p.state = p.next()
				return i + 1, ArrayEnd
			}

			p.push(_StateArrayCommaOrEnd)
			p.state = _StateValue
			i-- // rewind and let _StateValue do the parsing

		case _StateArrayCommaOrEnd:
			switch b {
			case ']':
				p.state = p.next()
				return i + 1, ArrayEnd
			case ',':
				p.push(_StateArrayCommaOrEnd)
				p.state = _StateValue
			default:
				return i, p.error(`_StateArrayCommaOrEnd: @todo`)
			}

		case _StateStringUnicode, _StateStringUnicode2,
			_StateStringUnicode3, _StateStringUnicode4:
			switch {
			case '0' <= b && b <= '9':
			case 'a' <= b && b <= 'f':
			case 'A' <= b && b <= 'F':
			default:
				return i, p.error(`_StateStringUnicodeX: @todo`)
			}

			p.state++ // note that `_StateString == (_StateStringUnicode4 + 1)`

		case _StateString:
			switch {
			case b == '"':
				p.state = p.next()
				return i + 1, StringEnd
			case b == '\\':
				p.state = _StateStringEscaped
			case b < 0x20:
				return i, p.error(`_StateString: @todo`)
			}

		case _StateStringEscaped:
			switch b {
			case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
				p.state = _StateString
			case 'u':
				p.state = _StateStringUnicode
			default:
				return i, p.error(`_StateStringEscaped: @todo`)
			}

		case _StateNumberNegative:
			switch {
			case b == '0':
				p.state = _StateNumberZero
			case '1' <= b && b <= '9':
				p.state = _StateNumber
			default:
				return i, p.error(`_StateNumberNegative: @todo`)
			}

		case _StateNumber:
			if '0' <= b && b <= '9' {
				break
			}
			fallthrough

		case _StateNumberZero:
			switch b {
			case '.':
				p.state = _StateNumberDotFirstDigit
			case 'e', 'E':
				p.state = _StateNumberExponentSign
			default:
				return i, p.error(`_StateNumberZero: @todo`)
			}

		case _StateNumberDotFirstDigit:
			if b < '0' || b > '9' {
				return i, p.error(`_StateNumberDot: @todo`)
			}
			p.state++

		case _StateNumberDotDigit:
			switch {
			case b == 'e', b == 'E':
				p.state = _StateNumberExponentSign
			case b < '0' || b > '9':
				return i, p.error(`_StateNumberDotDigit: @todo`)
			}

		case _StateNumberExponentSign:
			p.state++
			if b == '+' || b == '-' {
				break
			}
			fallthrough

		case _StateNumberExponentFirstDigit:
			if b < '0' || b > '9' {
				return i, p.error(`_StateNumberAfterExponent: @todo`)
			}
			p.state++

		case _StateNumberExponentDigit:
			if b < '0' || b > '9' {
				p.state = p.next()
				return i + 1, NumberEnd
			}

		case _StateTrue:
			if b != 'r' {
				return i, p.error(`_StateTrue: @todo`)
			}
			p.state++

		case _StateTrue2:
			if b != 'u' {
				return i, p.error(`_StateTrue2: @todo`)
			}
			p.state++

		case _StateTrue3:
			if b != 'e' {
				return i, p.error(`_StateTrue3: @todo`)
			}
			p.state = p.next()

			return i + 1, BoolEnd

		case _StateFalse:
			if b != 'a' {
				return i, p.error(`_StateFalse: @todo`)
			}
			p.state++

		case _StateFalse2:
			if b != 'l' {
				return i, p.error(`_StateFalse2: @todo`)
			}
			p.state++

		case _StateFalse3:
			if b != 's' {
				return i, p.error(`_StateFalse3: @todo`)
			}
			p.state++

		case _StateFalse4:
			if b != 'e' {
				return i, p.error(`_StateFalse4: @todo`)
			}
			p.state = p.next()

			return i + 1, BoolEnd

		case _StateNull:
			if b != 'u' {
				return i, p.error(`_StateNull: @todo`)
			}
			p.state++

		case _StateNull2:
			if b != 'l' {
				return i, p.error(`_StateNull2: @todo`)
			}
			p.state++

		case _StateNull3:
			if b != 'l' {
				return i, p.error(`_StateNull3: @todo`)
			}
			p.state = p.next()

			return i + 1, NullEnd

		case _StateDone:
			return i, p.error(`_StateDone: @todo`)

		default:
			panic(`invalid state`)
		}
	}

	return len(input), None
}

// Informs the parser not to expect any further input. Returns
// pending NumberEnd events if there are any, or a SyntaxError
// if EOF was not expected -- otherwise None.
func (p *Parser) Eof() Event {
	switch p.state {
	case _StateNumberZero,
		_StateNumber,
		_StateNumberDotDigit,
		_StateNumberExponentDigit:
		p.state = _StateDone
		return NumberEnd
	case _StateDone:
		return None
	}
	return p.error(`.Eof(): @todo`)
}

// Pops the next state off the parser struct's queue.
func (p *Parser) next() int {
	length := len(p.queue)

	// with the "state queue" empty, we can only wait for EOF
	if length == 0 {
		return _StateDone
	}

	state := p.queue[length]
	p.queue = p.queue[:length-1]

	return state
}

// Insert a new state at the top of the queue.
func (p *Parser) push(state int) {
	p.queue = append(p.queue, state)
}

// Registers a syntax error. Always returns a SyntaxError event.
func (p *Parser) error(message string) Event {
	p.err = syntaxError(message)
	return SyntaxError
}
<|endoftext|>


<commit_before>package liner

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

var (
	kernel32 = syscall.NewLazyDLL("kernel32.dll")

	procGetStdHandle               = kernel32.NewProc("GetStdHandle")
	procReadConsoleInput           = kernel32.NewProc("ReadConsoleInputW")
	procGetConsoleMode             = kernel32.NewProc("GetConsoleMode")
	procSetConsoleMode             = kernel32.NewProc("SetConsoleMode")
	procSetConsoleCursorPosition   = kernel32.NewProc("SetConsoleCursorPosition")
	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
	procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
)

const (
	std_input_handle  = uint32(-10 & 0xFFFFFFFF)
	std_output_handle = uint32(-11 & 0xFFFFFFFF)
	std_error_handle  = uint32(-12 & 0xFFFFFFFF)
)

type State struct {
	commonState
	handle   syscall.Handle
	hOut     syscall.Handle
	origMode uint32
	key      interface{}
	repeat   uint16
}

const (
	enableEchoInput      = 0x4
	enableInsertMode     = 0x20
	enableLineInput      = 0x2
	enableMouseInput     = 0x10
	enableProcessedInput = 0x1
	enableQuickEditMode  = 0x40
	enableWindowInput    = 0x8
)

func NewLiner() *State {
	var s State
	hIn, _, _ := procGetStdHandle.Call(uintptr(std_input_handle))
	s.handle = syscall.Handle(hIn)
	hOut, _, _ := procGetStdHandle.Call(uintptr(std_output_handle))
	s.hOut = syscall.Handle(hOut)

	ok, _, _ := procGetConsoleMode.Call(hIn, uintptr(unsafe.Pointer(&s.origMode)))
	if ok != 0 {
		mode := s.origMode
		mode &^= enableEchoInput
		mode &^= enableInsertMode
		mode &^= enableLineInput
		mode &^= enableMouseInput
		mode |= enableWindowInput
		procSetConsoleMode.Call(hIn, uintptr(mode))
	}

	s.supported = true
	return &s
}

const (
	focus_event              = 0x0010
	key_event                = 0x0001
	menu_event               = 0x0008
	mouse_event              = 0x0002
	window_buffer_size_event = 0x0004
)

type input_record struct {
	eventType uint16
	pad       uint16
	blob      [16]byte
}

type key_event_record struct {
	KeyDown         int32
	RepeatCount     uint16
	VirtualKeyCode  uint16
	VirtualScanCode uint16
	Char            int16
	ControlKeyState uint32
}

const (
	vk_tab    = 0x09
	vk_prior  = 0x21
	vk_next   = 0x22
	vk_end    = 0x23
	vk_home   = 0x24
	vk_left   = 0x25
	vk_up     = 0x26
	vk_right  = 0x27
	vk_down   = 0x28
	vk_insert = 0x2d
	vk_delete = 0x2e
	vk_f1     = 0x70
	vk_f2     = 0x71
	vk_f3     = 0x72
	vk_f4     = 0x73
	vk_f5     = 0x74
	vk_f6     = 0x75
	vk_f7     = 0x76
	vk_f8     = 0x77
	vk_f9     = 0x78
	vk_f10    = 0x79
	vk_f11    = 0x7a
	vk_f12    = 0x7b
)

const (
	shiftPressed     = 0x0010
	leftAltPressed   = 0x0002
	leftCtrlPressed  = 0x0008
	rightAltPressed  = 0x0001
	rightCtrlPressed = 0x0004

	modKeys = shiftPressed | leftAltPressed | rightAltPressed | leftCtrlPressed | rightCtrlPressed
)

func (s *State) readNext() (interface{}, error) {
	if s.repeat > 0 {
		s.repeat--
		return s.key, nil
	}

	var input input_record
	pbuf := uintptr(unsafe.Pointer(&input))
	var rv uint32
	prv := uintptr(unsafe.Pointer(&rv))

	for {
		ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv)

		if ok == 0 {
			return nil, err
		}

		if input.eventType == window_buffer_size_event {
			xy := (*coord)(unsafe.Pointer(&input.blob[0]))
			s.columns = int(xy.x)
			return winch, nil
		}
		if input.eventType != key_event {
			continue
		}
		ke := (*key_event_record)(unsafe.Pointer(&input.blob[0]))
		if ke.KeyDown == 0 {
			continue
		}

		if ke.VirtualKeyCode == vk_tab && ke.ControlKeyState&modKeys == shiftPressed {
			s.key = shiftTab
		} else if ke.Char > 0 {
			s.key = rune(ke.Char)
		} else {
			switch ke.VirtualKeyCode {
			case vk_prior:
				s.key = pageUp
			case vk_next:
				s.key = pageDown
			case vk_end:
				s.key = end
			case vk_home:
				s.key = home
			case vk_left:
				s.key = left
			case vk_right:
				s.key = right
			case vk_up:
				s.key = up
			case vk_down:
				s.key = down
			case vk_insert:
				s.key = insert
			case vk_delete:
				s.key = del
			case vk_f1:
				s.key = f1
			case vk_f2:
				s.key = f2
			case vk_f3:
				s.key = f3
			case vk_f4:
				s.key = f4
			case vk_f5:
				s.key = f5
			case vk_f6:
				s.key = f6
			case vk_f7:
				s.key = f7
			case vk_f8:
				s.key = f8
			case vk_f9:
				s.key = f9
			case vk_f10:
				s.key = f10
			case vk_f11:
				s.key = f11
			case vk_f12:
				s.key = f12
			default:
				// Eat modifier keys
				// TODO: return Action(Unknown) if the key isn't a
				// modifier.
				continue
			}
		}

		if ke.RepeatCount > 1 {
			s.repeat = ke.RepeatCount - 1
		}
		return s.key, nil
	}
	return unknown, nil
}

func (s *State) promptUnsupported(p string) (string, error) {
	return "", errors.New("Internal Error: Always supported on Windows")
}

func (s *State) Close() error {
	procSetConsoleMode.Call(uintptr(s.handle), uintptr(s.origMode))
	return nil
}
<commit_msg>Add ctrl-left and ctrl-right to the windows parser<commit_after>package liner

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

var (
	kernel32 = syscall.NewLazyDLL("kernel32.dll")

	procGetStdHandle               = kernel32.NewProc("GetStdHandle")
	procReadConsoleInput           = kernel32.NewProc("ReadConsoleInputW")
	procGetConsoleMode             = kernel32.NewProc("GetConsoleMode")
	procSetConsoleMode             = kernel32.NewProc("SetConsoleMode")
	procSetConsoleCursorPosition   = kernel32.NewProc("SetConsoleCursorPosition")
	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
	procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
)

const (
	std_input_handle  = uint32(-10 & 0xFFFFFFFF)
	std_output_handle = uint32(-11 & 0xFFFFFFFF)
	std_error_handle  = uint32(-12 & 0xFFFFFFFF)
)

type State struct {
	commonState
	handle   syscall.Handle
	hOut     syscall.Handle
	origMode uint32
	key      interface{}
	repeat   uint16
}

const (
	enableEchoInput      = 0x4
	enableInsertMode     = 0x20
	enableLineInput      = 0x2
	enableMouseInput     = 0x10
	enableProcessedInput = 0x1
	enableQuickEditMode  = 0x40
	enableWindowInput    = 0x8
)

func NewLiner() *State {
	var s State
	hIn, _, _ := procGetStdHandle.Call(uintptr(std_input_handle))
	s.handle = syscall.Handle(hIn)
	hOut, _, _ := procGetStdHandle.Call(uintptr(std_output_handle))
	s.hOut = syscall.Handle(hOut)

	ok, _, _ := procGetConsoleMode.Call(hIn, uintptr(unsafe.Pointer(&s.origMode)))
	if ok != 0 {
		mode := s.origMode
		mode &^= enableEchoInput
		mode &^= enableInsertMode
		mode &^= enableLineInput
		mode &^= enableMouseInput
		mode |= enableWindowInput
		procSetConsoleMode.Call(hIn, uintptr(mode))
	}

	s.supported = true
	return &s
}

const (
	focus_event              = 0x0010
	key_event                = 0x0001
	menu_event               = 0x0008
	mouse_event              = 0x0002
	window_buffer_size_event = 0x0004
)

type input_record struct {
	eventType uint16
	pad       uint16
	blob      [16]byte
}

type key_event_record struct {
	KeyDown         int32
	RepeatCount     uint16
	VirtualKeyCode  uint16
	VirtualScanCode uint16
	Char            int16
	ControlKeyState uint32
}

const (
	vk_tab    = 0x09
	vk_prior  = 0x21
	vk_next   = 0x22
	vk_end    = 0x23
	vk_home   = 0x24
	vk_left   = 0x25
	vk_up     = 0x26
	vk_right  = 0x27
	vk_down   = 0x28
	vk_insert = 0x2d
	vk_delete = 0x2e
	vk_f1     = 0x70
	vk_f2     = 0x71
	vk_f3     = 0x72
	vk_f4     = 0x73
	vk_f5     = 0x74
	vk_f6     = 0x75
	vk_f7     = 0x76
	vk_f8     = 0x77
	vk_f9     = 0x78
	vk_f10    = 0x79
	vk_f11    = 0x7a
	vk_f12    = 0x7b
)

const (
	shiftPressed     = 0x0010
	leftAltPressed   = 0x0002
	leftCtrlPressed  = 0x0008
	rightAltPressed  = 0x0001
	rightCtrlPressed = 0x0004

	modKeys = shiftPressed | leftAltPressed | rightAltPressed | leftCtrlPressed | rightCtrlPressed
)

func (s *State) readNext() (interface{}, error) {
	if s.repeat > 0 {
		s.repeat--
		return s.key, nil
	}

	var input input_record
	pbuf := uintptr(unsafe.Pointer(&input))
	var rv uint32
	prv := uintptr(unsafe.Pointer(&rv))

	for {
		ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv)

		if ok == 0 {
			return nil, err
		}

		if input.eventType == window_buffer_size_event {
			xy := (*coord)(unsafe.Pointer(&input.blob[0]))
			s.columns = int(xy.x)
			return winch, nil
		}
		if input.eventType != key_event {
			continue
		}
		ke := (*key_event_record)(unsafe.Pointer(&input.blob[0]))
		if ke.KeyDown == 0 {
			continue
		}

		if ke.VirtualKeyCode == vk_tab && ke.ControlKeyState&modKeys == shiftPressed {
			s.key = shiftTab
		} else if ke.Char > 0 {
			s.key = rune(ke.Char)
		} else {
			switch ke.VirtualKeyCode {
			case vk_prior:
				s.key = pageUp
			case vk_next:
				s.key = pageDown
			case vk_end:
				s.key = end
			case vk_home:
				s.key = home
			case vk_left:
				s.key = left
				if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 {
					if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) {
						s.key = wordLeft
					}
				}
			case vk_right:
				s.key = right
				if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 {
					if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) {
						s.key = wordRight
					}
				}
			case vk_up:
				s.key = up
			case vk_down:
				s.key = down
			case vk_insert:
				s.key = insert
			case vk_delete:
				s.key = del
			case vk_f1:
				s.key = f1
			case vk_f2:
				s.key = f2
			case vk_f3:
				s.key = f3
			case vk_f4:
				s.key = f4
			case vk_f5:
				s.key = f5
			case vk_f6:
				s.key = f6
			case vk_f7:
				s.key = f7
			case vk_f8:
				s.key = f8
			case vk_f9:
				s.key = f9
			case vk_f10:
				s.key = f10
			case vk_f11:
				s.key = f11
			case vk_f12:
				s.key = f12
			default:
				// Eat modifier keys
				// TODO: return Action(Unknown) if the key isn't a
				// modifier.
				continue
			}
		}

		if ke.RepeatCount > 1 {
			s.repeat = ke.RepeatCount - 1
		}
		return s.key, nil
	}
	return unknown, nil
}

func (s *State) promptUnsupported(p string) (string, error) {
	return "", errors.New("Internal Error: Always supported on Windows")
}

func (s *State) Close() error {
	procSetConsoleMode.Call(uintptr(s.handle), uintptr(s.origMode))
	return nil
}
<|endoftext|>


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

package parser

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/go-clang/v3.9/clang"
	"github.com/pkg/errors"
	"github.com/pkgutil/osutil"
	"github.com/pkgutil/stringsutil"
	"github.com/zchee/clang-server/compilationdatabase"
	"github.com/zchee/clang-server/indexdb"
	"github.com/zchee/clang-server/internal/log"
	"github.com/zchee/clang-server/internal/pathutil"
	"github.com/zchee/clang-server/parser/builtinheader"
	"github.com/zchee/clang-server/symbol"
)

// defaultClangOption defalut global clang options.
// clang.TranslationUnit_DetailedPreprocessingRecord = 0x01
// clang.TranslationUnit_Incomplete = 0x02
// clang.TranslationUnit_PrecompiledPreamble = 0x04
// clang.TranslationUnit_CacheCompletionResults = 0x08
// clang.TranslationUnit_ForSerialization = 0x10
// clang.TranslationUnit_CXXChainedPCH = 0x20
// clang.TranslationUnit_SkipFunctionBodies = 0x40
// clang.TranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80
// clang.TranslationUnit_CreatePreambleOnFirstParse = 0x100
// clang.TranslationUnit_KeepGoing = 0x200
// const defaultClangOption uint32 = 0x445 // Use all flags for now
var defaultClangOption = clang.DefaultEditingTranslationUnitOptions() | uint32(clang.TranslationUnit_KeepGoing)

// Parser represents a C/C++ AST parser.
type Parser struct {
	root        string
	clangOption uint32

	idx    clang.Index
	cd     *compilationdatabase.CompilationDatabase
	db     *indexdb.IndexDB
	server *symbol.Server

	dispatcher *dispatcher

	debugUncatched bool                     // for debug
	uncachedKind   map[clang.CursorKind]int // for debug
}

// Config represents a parser config.
type Config struct {
	Root        string
	JSONName    string
	PathRange   []string
	ClangOption uint32

	Debug bool
}

// NewParser return the new Parser.
func NewParser(path string, config *Config) *Parser {
	root := config.Root
	if root == "" {
		proot, err := pathutil.FindProjectRoot(path)
		if err != nil {
			log.Fatal(err)
		}
		root = proot
	}

	cd := compilationdatabase.NewCompilationDatabase(root)
	if err := cd.Parse(config.JSONName, config.PathRange); err != nil {
		log.Fatal(err)
	}

	db, err := indexdb.NewIndexDB(root)
	if err != nil {
		log.Fatal(err)
	}

	clangOption := config.ClangOption
	if clangOption == 0 {
		clangOption = defaultClangOption
	}

	p := &Parser{
		root:        root,
		clangOption: clangOption,
		idx:         clang.NewIndex(0, 0), // disable excludeDeclarationsFromPCH, enable displayDiagnostics
		cd:          cd,
		db:          db,
		server:      symbol.NewServer(),
	}

	if config.Debug {
		p.debugUncatched = true
		p.uncachedKind = make(map[clang.CursorKind]int)
	}

	if err := CreateBulitinHeaders(); err != nil {
		log.Fatal(err)
	}

	return p
}

// CreateBulitinHeaders creates(dumps) a clang builtin header to cache directory.
func CreateBulitinHeaders() error {
	builtinHdrDir := filepath.Join(pathutil.CacheDir(), "clang", "include")
	if !osutil.IsExist(builtinHdrDir) {
		if err := os.MkdirAll(builtinHdrDir, 0700); err != nil {
			return errors.WithStack(err)
		}
	}

	for _, fname := range builtinheader.AssetNames() {
		data, err := builtinheader.AssetInfo(fname)
		if err != nil {
			return errors.WithStack(err)
		}

		if strings.Contains(data.Name(), string(filepath.Separator)) {
			dir, _ := filepath.Split(data.Name())
			if err := os.MkdirAll(filepath.Join(builtinHdrDir, dir), 0700); err != nil {
				return errors.WithStack(err)
			}
		}

		buf, err := builtinheader.Asset(data.Name())
		if err != nil {
			return errors.WithStack(err)
		}

		if err := ioutil.WriteFile(filepath.Join(builtinHdrDir, data.Name()), buf, 0600); err != nil {
			return errors.WithStack(err)
		}
	}

	return nil
}

// Parse parses the project directories.
func (p *Parser) Parse() {
	defer func() {
		p.db.Close()
		p.server.Serve()
	}()
	defer profile(time.Now(), "Parse")

	ccs := p.cd.CompileCommands()
	if len(ccs) == 0 {
		log.Fatal("not walk")
	}

	compilerConfig := p.cd.CompilerConfig
	flags := append(compilerConfig.SystemCIncludeDir, compilerConfig.SystemFrameworkDir...)

	// TODO(zchee): needs include stdint.h?
	if i := stringsutil.IndexContainsSlice(ccs[0].Arguments, "-std="); i > 0 {
		std := ccs[0].Arguments[i][5:]
		switch {
		case strings.HasPrefix(std, "c"), strings.HasPrefix(std, "gnu"):
			if std[len(std)-2] == '8' || std[len(std)-2] == '9' || std[len(std)-2] == '1' {
				flags = append(flags, "-include", "/usr/include/stdint.h")
			}
		}
	} else {
		flags = append(flags, "-include", "/usr/include/stdint.h")
	}
	if !(filepath.Ext(ccs[0].File) == ".c") {
		flags = append(flags, compilerConfig.SystemCXXIncludeDir...)
	}

	builtinHdrDir := filepath.Join(pathutil.CacheDir(), "clang", "include")
	flags = append(flags, "-I"+builtinHdrDir)

	p.dispatcher = newDispatcher(p.ParseFile)
	p.dispatcher.Start()
	for i := 0; i < len(ccs); i++ {
		args := ccs[i].Arguments
		args = append(flags, args...)
		p.dispatcher.Add(parseArg{ccs[i].File, args})
	}
	p.dispatcher.Wait()
}

type parseArg struct {
	filename string
	flag     []string
}

// ParseFile parses the C/C++ file.
func (p *Parser) ParseFile(arg parseArg) error {
	var tu clang.TranslationUnit

	if p.db.Has(arg.filename) {
		buf, err := p.db.Get(arg.filename)
		if err != nil {
			return err
		}

		data := symbol.GetRootAsFile(buf, 0)
		tu, err = p.DeserializeTranslationUnit(p.idx, data.TranslationUnit())
		if err != nil {
			return err
		}
		defer tu.Dispose()

		log.Debugf("tu.Spelling(): %T => %+v\n", tu.Spelling(), tu.Spelling()) // for debug

		return nil
	}

	if cErr := p.idx.ParseTranslationUnit2(arg.filename, arg.flag, nil, p.clangOption, &tu); clang.ErrorCode(cErr) != clang.Error_Success {
		return errors.New(clang.ErrorCode(cErr).Spelling())
	}
	defer tu.Dispose()

	tuch := make(chan []byte, 1)
	go func() {
		tuch <- p.SerializeTranslationUnit(arg.filename, tu)
	}()

	// printDiagnostics(tu.Diagnostics())

	rootCursor := tu.TranslationUnitCursor()
	file := symbol.NewFile(arg.filename, arg.flag)
	visitNode := func(cursor, parent clang.Cursor) clang.ChildVisitResult {
		if cursor.IsNull() {
			log.Debug("cursor: <none>")
			return clang.ChildVisit_Continue
		}

		cursorLoc := symbol.FromCursor(cursor)
		if cursorLoc.FileName() == "" || cursorLoc.FileName() == "." {
			// TODO(zchee): Ignore system header(?)
			return clang.ChildVisit_Continue
		}

		kind := cursor.Kind()
		switch kind {
		case clang.Cursor_FunctionDecl, clang.Cursor_StructDecl, clang.Cursor_FieldDecl, clang.Cursor_TypedefDecl, clang.Cursor_EnumDecl, clang.Cursor_EnumConstantDecl:
			defCursor := cursor.Definition()
			if defCursor.IsNull() {
				file.AddDecl(cursorLoc)
			} else {
				defLoc := symbol.FromCursor(defCursor)
				file.AddDefinition(cursorLoc, defLoc)
			}
		case clang.Cursor_MacroDefinition:
			file.AddDefinition(cursorLoc, cursorLoc)
		case clang.Cursor_VarDecl:
			file.AddDecl(cursorLoc)
		case clang.Cursor_ParmDecl:
			if cursor.Spelling() != "" {
				file.AddDecl(cursorLoc)
			}
		case clang.Cursor_CallExpr:
			refCursor := cursor.Referenced()
			refLoc := symbol.FromCursor(refCursor)
			file.AddCaller(cursorLoc, refLoc, true)
		case clang.Cursor_DeclRefExpr, clang.Cursor_TypeRef, clang.Cursor_MemberRefExpr, clang.Cursor_MacroExpansion:
			refCursor := cursor.Referenced()
			refLoc := symbol.FromCursor(refCursor)
			file.AddCaller(cursorLoc, refLoc, false)
		case clang.Cursor_InclusionDirective:
			incFile := cursor.IncludedFile()
			file.AddHeader(cursor.Spelling(), incFile)
		default:
			if p.debugUncatched {
				p.uncachedKind[kind]++
			}
		}

		return clang.ChildVisit_Recurse
	}

	rootCursor.Visit(visitNode)
	file.AddTranslationUnit(<-tuch)
	buf := file.Serialize()

	out := symbol.GetRootAsFile(buf.FinishedBytes(), 0)
	printFile(out) // for debug

	log.Debugf("Goroutine:%d", runtime.NumGoroutine())
	log.Debugf("================== DONE: filename: %+v ==================\n\n\n", arg.filename)

	return p.db.Put(arg.filename, buf.FinishedBytes())
}

// SerializeTranslationUnit serialize the TranslationUnit to Clang serialized representation.
// TODO(zchee): Avoid ioutil.TempFile if possible.
func (p *Parser) SerializeTranslationUnit(filename string, tu clang.TranslationUnit) []byte {
	tmpFile, err := ioutil.TempFile(os.TempDir(), filepath.Base(filename))
	if err != nil {
		log.Fatal(err)
	}

	saveOptions := uint32(clang.TranslationUnit_KeepGoing)
	if cErr := tu.SaveTranslationUnit(tmpFile.Name(), saveOptions); clang.SaveError(cErr) != clang.SaveError_None {
		log.Fatal(clang.SaveError(cErr))
	}

	buf, err := ioutil.ReadFile(tmpFile.Name())
	if err != nil {
		log.Fatal(err)
	}
	os.Remove(tmpFile.Name())

	return buf
}

// DeserializeTranslationUnit deserialize the TranslationUnit from buf Clang serialized representation.
func (p *Parser) DeserializeTranslationUnit(idx clang.Index, buf []byte) (clang.TranslationUnit, error) {
	var tu clang.TranslationUnit

	tmpfile, err := ioutil.TempFile(os.TempDir(), "clang-server")
	if err != nil {
		return tu, err
	}
	defer tmpfile.Close()

	io.Copy(tmpfile, bytes.NewReader(buf))

	if err := idx.TranslationUnit2(tmpfile.Name(), &tu); clang.ErrorCode(err) != clang.Error_Success {
		return tu, errors.New(err.Spelling())
	}
	// finished create a translation unit from an AST file, remove tmpfile
	os.Remove(tmpfile.Name())

	return tu, nil
}

// ClangVersion return the current clang version.
func ClangVersion() string {
	return clang.GetClangVersion()
}
<commit_msg>parser: remove comment<commit_after>// Copyright 2016 The clang-server Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package parser

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/go-clang/v3.9/clang"
	"github.com/pkg/errors"
	"github.com/pkgutil/osutil"
	"github.com/pkgutil/stringsutil"
	"github.com/zchee/clang-server/compilationdatabase"
	"github.com/zchee/clang-server/indexdb"
	"github.com/zchee/clang-server/internal/log"
	"github.com/zchee/clang-server/internal/pathutil"
	"github.com/zchee/clang-server/parser/builtinheader"
	"github.com/zchee/clang-server/symbol"
)

// defaultClangOption defalut global clang options.
// clang.TranslationUnit_DetailedPreprocessingRecord = 0x01
// clang.TranslationUnit_Incomplete = 0x02
// clang.TranslationUnit_PrecompiledPreamble = 0x04
// clang.TranslationUnit_CacheCompletionResults = 0x08
// clang.TranslationUnit_ForSerialization = 0x10
// clang.TranslationUnit_CXXChainedPCH = 0x20
// clang.TranslationUnit_SkipFunctionBodies = 0x40
// clang.TranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80
// clang.TranslationUnit_CreatePreambleOnFirstParse = 0x100
// clang.TranslationUnit_KeepGoing = 0x200
// const defaultClangOption uint32 = 0x445 // Use all flags for now
var defaultClangOption = clang.DefaultEditingTranslationUnitOptions() | uint32(clang.TranslationUnit_KeepGoing)

// Parser represents a C/C++ AST parser.
type Parser struct {
	root        string
	clangOption uint32

	idx    clang.Index
	cd     *compilationdatabase.CompilationDatabase
	db     *indexdb.IndexDB
	server *symbol.Server

	dispatcher *dispatcher

	debugUncatched bool                     // for debug
	uncachedKind   map[clang.CursorKind]int // for debug
}

// Config represents a parser config.
type Config struct {
	Root        string
	JSONName    string
	PathRange   []string
	ClangOption uint32

	Debug bool
}

// NewParser return the new Parser.
func NewParser(path string, config *Config) *Parser {
	root := config.Root
	if root == "" {
		proot, err := pathutil.FindProjectRoot(path)
		if err != nil {
			log.Fatal(err)
		}
		root = proot
	}

	cd := compilationdatabase.NewCompilationDatabase(root)
	if err := cd.Parse(config.JSONName, config.PathRange); err != nil {
		log.Fatal(err)
	}

	db, err := indexdb.NewIndexDB(root)
	if err != nil {
		log.Fatal(err)
	}

	clangOption := config.ClangOption
	if clangOption == 0 {
		clangOption = defaultClangOption
	}

	p := &Parser{
		root:        root,
		clangOption: clangOption,
		idx:         clang.NewIndex(0, 0), // disable excludeDeclarationsFromPCH, enable displayDiagnostics
		cd:          cd,
		db:          db,
		server:      symbol.NewServer(),
	}

	if config.Debug {
		p.debugUncatched = true
		p.uncachedKind = make(map[clang.CursorKind]int)
	}

	if err := CreateBulitinHeaders(); err != nil {
		log.Fatal(err)
	}

	return p
}

// CreateBulitinHeaders creates(dumps) a clang builtin header to cache directory.
func CreateBulitinHeaders() error {
	builtinHdrDir := filepath.Join(pathutil.CacheDir(), "clang", "include")
	if !osutil.IsExist(builtinHdrDir) {
		if err := os.MkdirAll(builtinHdrDir, 0700); err != nil {
			return errors.WithStack(err)
		}
	}

	for _, fname := range builtinheader.AssetNames() {
		data, err := builtinheader.AssetInfo(fname)
		if err != nil {
			return errors.WithStack(err)
		}

		if strings.Contains(data.Name(), string(filepath.Separator)) {
			dir, _ := filepath.Split(data.Name())
			if err := os.MkdirAll(filepath.Join(builtinHdrDir, dir), 0700); err != nil {
				return errors.WithStack(err)
			}
		}

		buf, err := builtinheader.Asset(data.Name())
		if err != nil {
			return errors.WithStack(err)
		}

		if err := ioutil.WriteFile(filepath.Join(builtinHdrDir, data.Name()), buf, 0600); err != nil {
			return errors.WithStack(err)
		}
	}

	return nil
}

// Parse parses the project directories.
func (p *Parser) Parse() {
	defer func() {
		p.db.Close()
		p.server.Serve()
	}()
	defer profile(time.Now(), "Parse")

	ccs := p.cd.CompileCommands()
	if len(ccs) == 0 {
		log.Fatal("not walk")
	}

	compilerConfig := p.cd.CompilerConfig
	flags := append(compilerConfig.SystemCIncludeDir, compilerConfig.SystemFrameworkDir...)

	// TODO(zchee): needs include stdint.h?
	if i := stringsutil.IndexContainsSlice(ccs[0].Arguments, "-std="); i > 0 {
		std := ccs[0].Arguments[i][5:]
		switch {
		case strings.HasPrefix(std, "c"), strings.HasPrefix(std, "gnu"):
			if std[len(std)-2] == '8' || std[len(std)-2] == '9' || std[len(std)-2] == '1' {
				flags = append(flags, "-include", "/usr/include/stdint.h")
			}
		}
	} else {
		flags = append(flags, "-include", "/usr/include/stdint.h")
	}
	if !(filepath.Ext(ccs[0].File) == ".c") {
		flags = append(flags, compilerConfig.SystemCXXIncludeDir...)
	}

	builtinHdrDir := filepath.Join(pathutil.CacheDir(), "clang", "include")
	flags = append(flags, "-I"+builtinHdrDir)

	p.dispatcher = newDispatcher(p.ParseFile)
	p.dispatcher.Start()
	for i := 0; i < len(ccs); i++ {
		args := ccs[i].Arguments
		args = append(flags, args...)
		p.dispatcher.Add(parseArg{ccs[i].File, args})
	}
	p.dispatcher.Wait()
}

type parseArg struct {
	filename string
	flag     []string
}

// ParseFile parses the C/C++ file.
func (p *Parser) ParseFile(arg parseArg) error {
	var tu clang.TranslationUnit

	if p.db.Has(arg.filename) {
		buf, err := p.db.Get(arg.filename)
		if err != nil {
			return err
		}

		data := symbol.GetRootAsFile(buf, 0)
		tu, err = p.DeserializeTranslationUnit(p.idx, data.TranslationUnit())
		if err != nil {
			return err
		}
		defer tu.Dispose()

		log.Debugf("tu.Spelling(): %T => %+v\n", tu.Spelling(), tu.Spelling())

		return nil
	}

	if cErr := p.idx.ParseTranslationUnit2(arg.filename, arg.flag, nil, p.clangOption, &tu); clang.ErrorCode(cErr) != clang.Error_Success {
		return errors.New(clang.ErrorCode(cErr).Spelling())
	}
	defer tu.Dispose()

	tuch := make(chan []byte, 1)
	go func() {
		tuch <- p.SerializeTranslationUnit(arg.filename, tu)
	}()

	// printDiagnostics(tu.Diagnostics())

	rootCursor := tu.TranslationUnitCursor()
	file := symbol.NewFile(arg.filename, arg.flag)
	visitNode := func(cursor, parent clang.Cursor) clang.ChildVisitResult {
		if cursor.IsNull() {
			log.Debug("cursor: <none>")
			return clang.ChildVisit_Continue
		}

		cursorLoc := symbol.FromCursor(cursor)
		if cursorLoc.FileName() == "" || cursorLoc.FileName() == "." {
			// TODO(zchee): Ignore system header(?)
			return clang.ChildVisit_Continue
		}

		kind := cursor.Kind()
		switch kind {
		case clang.Cursor_FunctionDecl, clang.Cursor_StructDecl, clang.Cursor_FieldDecl, clang.Cursor_TypedefDecl, clang.Cursor_EnumDecl, clang.Cursor_EnumConstantDecl:
			defCursor := cursor.Definition()
			if defCursor.IsNull() {
				file.AddDecl(cursorLoc)
			} else {
				defLoc := symbol.FromCursor(defCursor)
				file.AddDefinition(cursorLoc, defLoc)
			}
		case clang.Cursor_MacroDefinition:
			file.AddDefinition(cursorLoc, cursorLoc)
		case clang.Cursor_VarDecl:
			file.AddDecl(cursorLoc)
		case clang.Cursor_ParmDecl:
			if cursor.Spelling() != "" {
				file.AddDecl(cursorLoc)
			}
		case clang.Cursor_CallExpr:
			refCursor := cursor.Referenced()
			refLoc := symbol.FromCursor(refCursor)
			file.AddCaller(cursorLoc, refLoc, true)
		case clang.Cursor_DeclRefExpr, clang.Cursor_TypeRef, clang.Cursor_MemberRefExpr, clang.Cursor_MacroExpansion:
			refCursor := cursor.Referenced()
			refLoc := symbol.FromCursor(refCursor)
			file.AddCaller(cursorLoc, refLoc, false)
		case clang.Cursor_InclusionDirective:
			incFile := cursor.IncludedFile()
			file.AddHeader(cursor.Spelling(), incFile)
		default:
			if p.debugUncatched {
				p.uncachedKind[kind]++
			}
		}

		return clang.ChildVisit_Recurse
	}

	rootCursor.Visit(visitNode)
	file.AddTranslationUnit(<-tuch)
	buf := file.Serialize()

	out := symbol.GetRootAsFile(buf.FinishedBytes(), 0)
	printFile(out) // for debug

	log.Debugf("Goroutine:%d", runtime.NumGoroutine())
	log.Debugf("================== DONE: filename: %+v ==================\n\n\n", arg.filename)

	return p.db.Put(arg.filename, buf.FinishedBytes())
}

// SerializeTranslationUnit serialize the TranslationUnit to Clang serialized representation.
// TODO(zchee): Avoid ioutil.TempFile if possible.
func (p *Parser) SerializeTranslationUnit(filename string, tu clang.TranslationUnit) []byte {
	tmpFile, err := ioutil.TempFile(os.TempDir(), filepath.Base(filename))
	if err != nil {
		log.Fatal(err)
	}

	saveOptions := uint32(clang.TranslationUnit_KeepGoing)
	if cErr := tu.SaveTranslationUnit(tmpFile.Name(), saveOptions); clang.SaveError(cErr) != clang.SaveError_None {
		log.Fatal(clang.SaveError(cErr))
	}

	buf, err := ioutil.ReadFile(tmpFile.Name())
	if err != nil {
		log.Fatal(err)
	}
	os.Remove(tmpFile.Name())

	return buf
}

// DeserializeTranslationUnit deserialize the TranslationUnit from buf Clang serialized representation.
func (p *Parser) DeserializeTranslationUnit(idx clang.Index, buf []byte) (clang.TranslationUnit, error) {
	var tu clang.TranslationUnit

	tmpfile, err := ioutil.TempFile(os.TempDir(), "clang-server")
	if err != nil {
		return tu, err
	}
	defer tmpfile.Close()

	io.Copy(tmpfile, bytes.NewReader(buf))

	if err := idx.TranslationUnit2(tmpfile.Name(), &tu); clang.ErrorCode(err) != clang.Error_Success {
		return tu, errors.New(err.Spelling())
	}
	// finished create a translation unit from an AST file, remove tmpfile
	os.Remove(tmpfile.Name())

	return tu, nil
}

// ClangVersion return the current clang version.
func ClangVersion() string {
	return clang.GetClangVersion()
}
<|endoftext|>


<commit_before>// Copyright 2016 Alexander Palaistras. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

package parser

import (
	// Standard library.
	"fmt"
	"io"
)

// Parser is an interface that wraps the Parse method.
type Parser interface {
	Parse(io.Reader) (Document, error)
}

// Document is an interface that represents a generic, introspect-able document.
type Document interface {
	Filter(attr string) (Document, error)
	Slice() []Document
	String() string
}

// A map of all registered parsers.
var parsers map[string]Parser

// Register a parser under a unique name.
func Register(name string, rcvr Parser) error {
	if _, exists := parsers[name]; exists {
		return fmt.Errorf("Parser '%s' already registered, refusing to overwrite", name)
	}

	parsers[name] = rcvr
	return nil
}

// Read and parse document by calling the appropriate concrete parser for the kind
// passed. Returns a parsed document, which can then be queried against, or an
// error if parsing fails.
func Parse(kind string, src io.Reader) (Document, error) {
	if _, exists := parsers[kind]; !exists {
		return nil, fmt.Errorf("Parser for '%s' not found", kind)
	}

	return parsers[kind].Parse(src)
}

func init() {
	parsers = make(map[string]Parser)
}
<commit_msg>parser.go: Fix comment on Parse method for golint<commit_after>// Copyright 2016 Alexander Palaistras. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

package parser

import (
	// Standard library.
	"fmt"
	"io"
)

// Parser is an interface that wraps the Parse method.
type Parser interface {
	Parse(io.Reader) (Document, error)
}

// Document is an interface that represents a generic, introspect-able document.
type Document interface {
	Filter(attr string) (Document, error)
	Slice() []Document
	String() string
}

// A map of all registered parsers.
var parsers map[string]Parser

// Register a parser under a unique name.
func Register(name string, rcvr Parser) error {
	if _, exists := parsers[name]; exists {
		return fmt.Errorf("Parser '%s' already registered, refusing to overwrite", name)
	}

	parsers[name] = rcvr
	return nil
}

// Parse calls the appropriate concrete parser for the kind passed. Returns a
// parsed document, which can then be queried against, or an error if parsing fails.
func Parse(kind string, src io.Reader) (Document, error) {
	if _, exists := parsers[kind]; !exists {
		return nil, fmt.Errorf("Parser for '%s' not found", kind)
	}

	return parsers[kind].Parse(src)
}

func init() {
	parsers = make(map[string]Parser)
}
<|endoftext|>


<commit_before>package iochan

import (
	"bufio"
	"io"
)

type Mode int

const (
	Delimiter Mode = iota
	Timer
	Size
)

// ReaderDelimiter reads from io.Reader till delimiter, send readed bytes to channel
// works while io.Reader
func ReaderDelimiter(r io.Reader, delimiter byte) <-chan string {
	ch := make(chan string)

	go func() {
		buf := bufio.NewReader(r)

		for {
			line, err := buf.ReadString(delimiter)
			if err != nil {
				break
			}

			ch <- line
		}

		close(ch)
	}()

	return ch
}

// ReaderSize reads from io.Reader upto size, send readed bytes to channel
func ReaderSize(r io.Reader, size int) <-chan string {
	ch := make(chan string)

	go func() {
		buf := bufio.NewReader(r)

		for {
			line := make([]byte, size)
			if _, err := buf.Read(line); err != nil {
				break
			}

			ch <- string(line)
		}

		close(ch)
	}()

	return ch
}
<commit_msg>iochan: chan writer<commit_after>package iochan

import (
	"bufio"
	"bytes"
	"io"
	"time"
)

// DelimReader reads from io.Reader till delimiter, send readed bytes to channel
// works while io.Reader
func DelimReader(r io.Reader, delimiter byte) <-chan string {
	ch := make(chan string)

	go func() {
		buf := bufio.NewReader(r)

		for {
			line, err := buf.ReadString(delimiter)
			if err != nil {
				break
			}

			ch <- line
		}

		close(ch)
	}()

	return ch
}

// SizeReader reads from io.Reader upto size, send readed bytes to channel
func SizeReader(r io.Reader, size int) <-chan string {
	ch := make(chan string)

	go func() {
		buf := bufio.NewReader(r)

		for {
			line := make([]byte, size)
			if _, err := buf.Read(line); err != nil {
				break
			}

			ch <- string(line)
		}

		close(ch)
	}()

	return ch
}

// TimedWrite reads from chan and writes to w when timer expires
func TimedWrite(ch <-chan string, timer time.Duration, w io.Writer) {
	go func() {
		var buf bytes.Buffer

		for {
			select {
			case data := <-ch:
				buf.WriteString(data)

			case <-time.After(timer):
				w.Write(buf.Bytes())
				buf.Reset()
			}
		}
	}()
}

// SizedWrite reads from chan and writes to w when data exceeds size bytes
func SizedWrite(ch <-chan string, size int, w io.Writer) {
	go func() {
		var buf bytes.Buffer

		for {
			data := <-ch
			buf.WriteString(data)

			if buf.Len() >= size {
				w.Write(buf.Bytes())
				buf.Reset()
			}
		}
	}()
}
<|endoftext|>


<commit_before>package aws

import(
    "fmt"
//    "math/rand"
//    "strings"
    "testing"
//    "time"
//
    "github.com/awslabs/aws-sdk-go/aws"
    "github.com/awslabs/aws-sdk-go/service/cloudwatch"
    "github.com/hashicorp/terraform/helper/resource"
    "github.com/hashicorp/terraform/terraform"
)

func TestAccAWSCloudWatchMetricAlarm_basic(t* testing.T) {
    var alarm cloudwatch.MetricAlarm

    resource.Test(t, resource.TestCase{
        PreCheck:       func () { testAccPreCheck(t) },
        Providers:      testAccProviders,
        CheckDestroy:   testAccCheckAWSCloudWatchMetricAlarmDestroy,
        Steps:          []resource.TestStep{
            resource.TestStep{
                Config: testAccAWSCloudWatchMetricAlarmConfig,
                Check:  resource.ComposeTestCheckFunc(
                    testAccCheckCloudWatchMetricAlarmExists("aws_cloudwatch_metric_alarm.foobar", &alarm),
                    resource.TestCheckResourceAttr("aws_cloudwatch_metric_alarm.foobar", "", ""),
                    resource.TestCheckResourceAttr("aws_cloudwatch_metric_alarm.foobar", "", ""),
                ),
            },
        },
    })
}

func testAccCheckCloudWatchMetricAlarmExists(n string, alarm *cloudwatch.MetricAlarm) resource.TestCheckFunc {
    return func(s *terraform.State) error {
        rs, ok := s.RootModule().Resources[n]
        if !ok {
            return fmt.Errorf("Not found: %s", n)
        }

        conn := testAccProvider.Meta().(*AWSClient).cloudwatchconn
        params := cloudwatch.DescribeAlarmsInput{
            AlarmNames: []*string{aws.String(rs.Primary.ID)},
        }
        resp, err := conn.DescribeAlarms(&params)
        if err != nil {
            return err
        }
        if len(resp.MetricAlarms) == 0 {
            return fmt.Errorf("Alarm not found")
        }
        *alarm = *resp.MetricAlarms[0]

        return nil
    }
}

func testAccCheckAWSCloudWatchMetricAlarmDestroy(s *terraform.State) error {
    return nil
}

var testAccAWSCloudWatchMetricAlarmConfig = fmt.Sprintf(`
resource "aws_cloudwatch_metric_alarm" "foobar" {
    alarm_name = "terraform-test-foobar5"
    comparison_operator = "GreaterThanOrEqualToThreshold"
    evaluation_periods = "2"
    metric_name = "CPUUtilization"
    namespace = "AWS/EC2"
    period = "120"
    statistic = "Average"
    threshold = "80"
    alarm_description = "This metric monitor ec2 cpu utilization"
    insufficient_data_actions = []
}
`)
<commit_msg>Added some attribute checks<commit_after>package aws

import(
    "fmt"
//    "math/rand"
//    "strings"
    "testing"
//    "time"
//
    "github.com/awslabs/aws-sdk-go/aws"
    "github.com/awslabs/aws-sdk-go/service/cloudwatch"
    "github.com/hashicorp/terraform/helper/resource"
    "github.com/hashicorp/terraform/terraform"
)

func TestAccAWSCloudWatchMetricAlarm_basic(t* testing.T) {
    var alarm cloudwatch.MetricAlarm

    resource.Test(t, resource.TestCase{
        PreCheck:       func () { testAccPreCheck(t) },
        Providers:      testAccProviders,
        CheckDestroy:   testAccCheckAWSCloudWatchMetricAlarmDestroy,
        Steps:          []resource.TestStep{
            resource.TestStep{
                Config: testAccAWSCloudWatchMetricAlarmConfig,
                Check:  resource.ComposeTestCheckFunc(
                    testAccCheckCloudWatchMetricAlarmExists("aws_cloudwatch_metric_alarm.foobar", &alarm),
                    resource.TestCheckResourceAttr("aws_cloudwatch_metric_alarm.foobar", "metric_name", "CPUUtilization"),
                    resource.TestCheckResourceAttr("aws_cloudwatch_metric_alarm.foobar", "statistic", "Average"),
                ),
            },
        },
    })
}

func testAccCheckCloudWatchMetricAlarmExists(n string, alarm *cloudwatch.MetricAlarm) resource.TestCheckFunc {
    return func(s *terraform.State) error {
        rs, ok := s.RootModule().Resources[n]
        if !ok {
            return fmt.Errorf("Not found: %s", n)
        }

        conn := testAccProvider.Meta().(*AWSClient).cloudwatchconn
        params := cloudwatch.DescribeAlarmsInput{
            AlarmNames: []*string{aws.String(rs.Primary.ID)},
        }
        resp, err := conn.DescribeAlarms(&params)
        if err != nil {
            return err
        }
        if len(resp.MetricAlarms) == 0 {
            return fmt.Errorf("Alarm not found")
        }
        *alarm = *resp.MetricAlarms[0]

        return nil
    }
}

func testAccCheckAWSCloudWatchMetricAlarmDestroy(s *terraform.State) error {
    return nil
}

var testAccAWSCloudWatchMetricAlarmConfig = fmt.Sprintf(`
resource "aws_cloudwatch_metric_alarm" "foobar" {
    alarm_name = "terraform-test-foobar5"
    comparison_operator = "GreaterThanOrEqualToThreshold"
    evaluation_periods = "2"
    metric_name = "CPUUtilization"
    namespace = "AWS/EC2"
    period = "120"
    statistic = "Average"
    threshold = "80"
    alarm_description = "This metric monitor ec2 cpu utilization"
    insufficient_data_actions = []
}
`)
<|endoftext|>


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

package clevergo

import (
	"fmt"
	"github.com/valyala/fasthttp"
	"os"
	"time"
)

const (
	Version = "1.0.0"
	Logo    = `  ____ _     _______     _______ ____   ____  ___
 / ___| |   | ____\ \   / / ____|  _ \ / ___|/ _ \
| |   | |   |  _|  \ \ / /|  _| | |_) | |  _| | | |
| |___| |___| |___  \ V / | |___|  _ <| |_| | |_| |
 \____|_____|_____|  \_/  |_____|_| \_\\____|\___/ `
)

func Run() {
	fmt.Printf("\x1b[36;1m%s %s\x1b[0m\n\n\x1b[32;1mStarted at %s\x1b[0m\n", Logo, Version, time.Now())
}

func ListenAndServe(addr string, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServe(addr, handler)
}

func ListenAndServeUNIX(addr string, mode os.FileMode, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServeUNIX(addr, mode, handler)
}

func ListenAndServeTLS(addr, certFile, keyFile string, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServeTLS(addr, certFile, keyFile, handler)
}

func ListenAndServeTLSEmbed(addr string, certData, keyData []byte, handler fasthttp.RequestHandler) error {
	Run()
	return fasthttp.ListenAndServeTLSEmbed(addr, certData, keyData, handler)
}
<commit_msg>Changed clevergo version and renamed Run() to info()<commit_after>// Copyright 2016 HeadwindFly. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package clevergo

import (
	"fmt"
	"github.com/valyala/fasthttp"
	"os"
	"time"
)

const (
	Version = "1.0.2"
	Logo    = `  ____ _     _______     _______ ____   ____  ___
 / ___| |   | ____\ \   / / ____|  _ \ / ___|/ _ \
| |   | |   |  _|  \ \ / /|  _| | |_) | |  _| | | |
| |___| |___| |___  \ V / | |___|  _ <| |_| | |_| |
 \____|_____|_____|  \_/  |_____|_| \_\\____|\___/ `
)

func info() {
	fmt.Printf("\x1b[36;1m%s %s\x1b[0m\n\n\x1b[32;1mStarted at %s\x1b[0m\n", Logo, Version, time.Now())
}

func ListenAndServe(addr string, handler fasthttp.RequestHandler) error {
	info()
	return fasthttp.ListenAndServe(addr, handler)
}

func ListenAndServeUNIX(addr string, mode os.FileMode, handler fasthttp.RequestHandler) error {
	info()
	return fasthttp.ListenAndServeUNIX(addr, mode, handler)
}

func ListenAndServeTLS(addr, certFile, keyFile string, handler fasthttp.RequestHandler) error {
	info()
	return fasthttp.ListenAndServeTLS(addr, certFile, keyFile, handler)
}

func ListenAndServeTLSEmbed(addr string, certData, keyData []byte, handler fasthttp.RequestHandler) error {
	info()
	return fasthttp.ListenAndServeTLSEmbed(addr, certData, keyData, handler)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/docker/docker/pkg/reexec"
	"github.com/golang/glog"
	"github.com/hyperhq/runv/driverloader"
	"github.com/hyperhq/runv/hypervisor"
	"github.com/urfave/cli"
)

var (
	version   = ""
	gitCommit = ""
)

const (
	specConfig  = "config.json"
	stateJSON   = "state.json"
	processJSON = "process.json"
	usage       = `Open Container Initiative hypervisor-based runtime

runv is a command line client for running applications packaged according to
the Open Container Format (OCF) and is a compliant implementation of the
Open Container Initiative specification.  However, due to the difference
between hypervisors and containers, the following sections of OCF don't
apply to runV:
    Namespace
    Capability
    Device
    "linux" and "mount" fields in OCI specs are ignored

The current release of "runV" supports the following hypervisors:
    KVM (QEMU 2.0 or later)
    Xen (4.5 or later)
    VirtualBox (Mac OS X)

After creating a spec for your root filesystem, you can execute a container
in your shell by running:

    # cd /mycontainer
    # runv run [ -b bundle ] <container-id>

If not specified, the default value for the 'bundle' is the current directory.
'Bundle' is the directory where '` + specConfig + `' must be located.`
)

func main() {
	if reexec.Init() {
		return
	}

	app := cli.NewApp()
	app.Name = "runv"
	app.Usage = usage
	app.Version = fmt.Sprintf("%s, commit: %s", version, gitCommit)
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug",
			Usage: "enable debug output for logging, saved on the dir specified by log_dir via glog style",
		},
		cli.StringFlag{
			Name:  "log_dir",
			Value: "/var/log/hyper",
			Usage: "the directory for the logging (glog style)",
		},
		cli.StringFlag{
			Name:  "log",
			Usage: "[ignored on runv] set the log file path where internal debug information is written",
		},
		cli.StringFlag{
			Name:  "log-format",
			Usage: "[ignored on runv] set the format used by logs ('text' (default), or 'json')",
		},
		cli.StringFlag{
			Name:  "root",
			Value: "/run/runv",
			Usage: "root directory for storage of container state (this should be located in tmpfs)",
		},
		cli.StringFlag{
			Name:  "driver",
			Usage: "hypervisor driver (supports: kvm xen vbox)",
		},
		cli.IntFlag{
			Name:  "default_cpus",
			Usage: "default number of vcpus to assign pod",
			Value: 1,
		},
		cli.IntFlag{
			Name:  "default_memory",
			Usage: "default memory to assign pod (mb)",
			Value: 128,
		},
		cli.StringFlag{
			Name:  "kernel",
			Usage: "kernel for the container",
		},
		cli.StringFlag{
			Name:  "initrd",
			Usage: "runv-compatible initrd for the container",
		},
		cli.StringFlag{
			Name:  "bios",
			Usage: "bios for the container",
		},
		cli.StringFlag{
			Name:  "cbfs",
			Usage: "cbfs for the container",
		},
		cli.StringFlag{
			Name:  "template",
			Usage: "path to the template vm state directory",
		},
		cli.StringFlag{
			Name:  "vbox",
			Usage: "runv-compatible boot ISO for the container for vbox driver",
		},
	}
	app.After = func(context *cli.Context) error {
		// make sure glog flush all the messages to file
		glog.Flush()
		return nil
	}

	app.Commands = []cli.Command{
		createCommand,
		execCommand,
		killCommand,
		listCommand,
		psCommand,
		runCommand,
		specCommand,
		startCommand,
		stateCommand,
		manageCommand,
		pauseCommand,
		resumeCommand,
		deleteCommand,
		proxyCommand,
		shimCommand,
		nsListenCommand,
	}
	if err := app.Run(os.Args); err != nil {
		glog.Errorf("app.Run(os.Args) failed with err: %#v", err)
		fmt.Fprintf(os.Stderr, "%v\n", err)
	}
}

// runvOptions is used for create aux runv processes (networklistener/shim/proxy)
type runvOptions struct {
	*cli.Context
	withContainer *State
	attach        bool
}

func cmdPrepare(context *cli.Context, setupHypervisor, canLogToStderr bool) error {
	if setupHypervisor {
		var err error
		if hypervisor.HDriver, err = driverloader.Probe(context.GlobalString("driver")); err != nil {
			return err
		}
		setupHyperstartFunc(context)
	}

	logdir := context.GlobalString("log_dir")
	if logdir != "" {
		if err := os.MkdirAll(logdir, 0750); err != nil {
			return fmt.Errorf("can't create dir %q for log files", logdir)
		}
	}
	if !context.GlobalBool("debug") {
		flag.CommandLine.Parse([]string{"-v", "1", "--log_dir", logdir})
	} else if canLogToStderr {
		flag.CommandLine.Parse([]string{"-v", "3", "--log_dir", logdir, "--alsologtostderr"})
	} else {
		flag.CommandLine.Parse([]string{"-v", "3", "--log_dir", logdir})
	}
	return nil
}
<commit_msg>set a default exit code in main<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/docker/docker/pkg/reexec"
	"github.com/golang/glog"
	"github.com/hyperhq/runv/driverloader"
	"github.com/hyperhq/runv/hypervisor"
	"github.com/urfave/cli"
)

var (
	version   = ""
	gitCommit = ""
)

const (
	specConfig  = "config.json"
	stateJSON   = "state.json"
	processJSON = "process.json"
	usage       = `Open Container Initiative hypervisor-based runtime

runv is a command line client for running applications packaged according to
the Open Container Format (OCF) and is a compliant implementation of the
Open Container Initiative specification.  However, due to the difference
between hypervisors and containers, the following sections of OCF don't
apply to runV:
    Namespace
    Capability
    Device
    "linux" and "mount" fields in OCI specs are ignored

The current release of "runV" supports the following hypervisors:
    KVM (QEMU 2.0 or later)
    Xen (4.5 or later)
    VirtualBox (Mac OS X)

After creating a spec for your root filesystem, you can execute a container
in your shell by running:

    # cd /mycontainer
    # runv run [ -b bundle ] <container-id>

If not specified, the default value for the 'bundle' is the current directory.
'Bundle' is the directory where '` + specConfig + `' must be located.`
)

func main() {
	if reexec.Init() {
		return
	}

	app := cli.NewApp()
	app.Name = "runv"
	app.Usage = usage
	app.Version = fmt.Sprintf("%s, commit: %s", version, gitCommit)
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug",
			Usage: "enable debug output for logging, saved on the dir specified by log_dir via glog style",
		},
		cli.StringFlag{
			Name:  "log_dir",
			Value: "/var/log/hyper",
			Usage: "the directory for the logging (glog style)",
		},
		cli.StringFlag{
			Name:  "log",
			Usage: "[ignored on runv] set the log file path where internal debug information is written",
		},
		cli.StringFlag{
			Name:  "log-format",
			Usage: "[ignored on runv] set the format used by logs ('text' (default), or 'json')",
		},
		cli.StringFlag{
			Name:  "root",
			Value: "/run/runv",
			Usage: "root directory for storage of container state (this should be located in tmpfs)",
		},
		cli.StringFlag{
			Name:  "driver",
			Usage: "hypervisor driver (supports: kvm xen vbox)",
		},
		cli.IntFlag{
			Name:  "default_cpus",
			Usage: "default number of vcpus to assign pod",
			Value: 1,
		},
		cli.IntFlag{
			Name:  "default_memory",
			Usage: "default memory to assign pod (mb)",
			Value: 128,
		},
		cli.StringFlag{
			Name:  "kernel",
			Usage: "kernel for the container",
		},
		cli.StringFlag{
			Name:  "initrd",
			Usage: "runv-compatible initrd for the container",
		},
		cli.StringFlag{
			Name:  "bios",
			Usage: "bios for the container",
		},
		cli.StringFlag{
			Name:  "cbfs",
			Usage: "cbfs for the container",
		},
		cli.StringFlag{
			Name:  "template",
			Usage: "path to the template vm state directory",
		},
		cli.StringFlag{
			Name:  "vbox",
			Usage: "runv-compatible boot ISO for the container for vbox driver",
		},
	}
	app.After = func(context *cli.Context) error {
		// make sure glog flush all the messages to file
		glog.Flush()
		return nil
	}

	app.Commands = []cli.Command{
		createCommand,
		execCommand,
		killCommand,
		listCommand,
		psCommand,
		runCommand,
		specCommand,
		startCommand,
		stateCommand,
		manageCommand,
		pauseCommand,
		resumeCommand,
		deleteCommand,
		proxyCommand,
		shimCommand,
		nsListenCommand,
	}
	if err := app.Run(os.Args); err != nil {
		glog.Errorf("app.Run(os.Args) failed with err: %#v", err)
		fmt.Fprintf(os.Stderr, "%v\n", err)
		cli.HandleExitCoder(err)
		// non-standard errors
		os.Exit(22)
	}
}

// runvOptions is used for create aux runv processes (networklistener/shim/proxy)
type runvOptions struct {
	*cli.Context
	withContainer *State
	attach        bool
}

func cmdPrepare(context *cli.Context, setupHypervisor, canLogToStderr bool) error {
	if setupHypervisor {
		var err error
		if hypervisor.HDriver, err = driverloader.Probe(context.GlobalString("driver")); err != nil {
			return err
		}
		setupHyperstartFunc(context)
	}

	logdir := context.GlobalString("log_dir")
	if logdir != "" {
		if err := os.MkdirAll(logdir, 0750); err != nil {
			return fmt.Errorf("can't create dir %q for log files", logdir)
		}
	}
	if !context.GlobalBool("debug") {
		flag.CommandLine.Parse([]string{"-v", "1", "--log_dir", logdir})
	} else if canLogToStderr {
		flag.CommandLine.Parse([]string{"-v", "3", "--log_dir", logdir, "--alsologtostderr"})
	} else {
		flag.CommandLine.Parse([]string{"-v", "3", "--log_dir", logdir})
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
// released under the MIT license

package irc

import (
	"errors"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/websocket"

	"github.com/oragono/oragono/irc/utils"
)

var (
	errCantReloadListener = errors.New("can't switch a listener between stream and websocket")
)

// IRCListener is an abstract wrapper for a listener (TCP port or unix domain socket).
// Server tracks these by listen address and can reload or stop them during rehash.
type IRCListener interface {
	Reload(config utils.ListenerConfig) error
	Stop() error
}

// NewListener creates a new listener according to the specifications in the config file
func NewListener(server *Server, addr string, config utils.ListenerConfig, bindMode os.FileMode) (result IRCListener, err error) {
	baseListener, err := createBaseListener(addr, bindMode)
	if err != nil {
		return
	}

	wrappedListener := utils.NewReloadableListener(baseListener, config)

	if config.WebSocket {
		return NewWSListener(server, addr, wrappedListener, config)
	} else {
		return NewNetListener(server, addr, wrappedListener, config)
	}
}

func createBaseListener(addr string, bindMode os.FileMode) (listener net.Listener, err error) {
	addr = strings.TrimPrefix(addr, "unix:")
	if strings.HasPrefix(addr, "/") {
		// https://stackoverflow.com/a/34881585
		os.Remove(addr)
		listener, err = net.Listen("unix", addr)
		if err == nil && bindMode != 0 {
			os.Chmod(addr, bindMode)
		}
	} else {
		listener, err = net.Listen("tcp", addr)
	}
	return
}

// NetListener is an IRCListener for a regular stream socket (TCP or unix domain)
type NetListener struct {
	listener *utils.ReloadableListener
	server   *Server
	addr     string
}

func NewNetListener(server *Server, addr string, listener *utils.ReloadableListener, config utils.ListenerConfig) (result *NetListener, err error) {
	nl := NetListener{
		server:   server,
		listener: listener,
		addr:     addr,
	}
	go nl.serve()
	return &nl, nil
}

func (nl *NetListener) Reload(config utils.ListenerConfig) error {
	if config.WebSocket {
		return errCantReloadListener
	}
	nl.listener.Reload(config)
	return nil
}

func (nl *NetListener) Stop() error {
	return nl.listener.Close()
}

func (nl *NetListener) serve() {
	for {
		conn, err := nl.listener.Accept()

		if err == nil {
			// hand off the connection
			wConn, ok := conn.(*utils.WrappedConn)
			if ok {
				confirmProxyData(wConn, "", "", "", nl.server.Config())
				go nl.server.RunClient(NewIRCStreamConn(wConn))
			} else {
				nl.server.logger.Error("internal", "invalid connection type", nl.addr)
			}
		} else if err == utils.ErrNetClosing {
			return
		} else {
			nl.server.logger.Error("internal", "accept error", nl.addr, err.Error())
		}
	}
}

// WSListener is a listener for IRC-over-websockets (initially HTTP, then upgraded to a
// different application protocol that provides a message-based API, possibly with TLS)
type WSListener struct {
	sync.Mutex // tier 1
	listener   *utils.ReloadableListener
	httpServer *http.Server
	server     *Server
	addr       string
	config     utils.ListenerConfig
}

func NewWSListener(server *Server, addr string, listener *utils.ReloadableListener, config utils.ListenerConfig) (result *WSListener, err error) {
	result = &WSListener{
		listener: listener,
		server:   server,
		addr:     addr,
		config:   config,
	}
	result.httpServer = &http.Server{
		Handler:      http.HandlerFunc(result.handle),
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
	}
	go result.httpServer.Serve(listener)
	return
}

func (wl *WSListener) Reload(config utils.ListenerConfig) error {
	if !config.WebSocket {
		return errCantReloadListener
	}
	wl.listener.Reload(config)
	return nil
}

func (wl *WSListener) Stop() error {
	return wl.httpServer.Close()
}

func (wl *WSListener) handle(w http.ResponseWriter, r *http.Request) {
	config := wl.server.Config()
	remoteAddr := r.RemoteAddr
	xff := r.Header.Get("X-Forwarded-For")
	xfp := r.Header.Get("X-Forwarded-Proto")

	wsUpgrader := websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			if len(config.Server.WebSockets.allowedOriginRegexps) == 0 {
				return true
			}
			origin := strings.TrimSpace(r.Header.Get("Origin"))
			if len(origin) == 0 {
				return false
			}
			for _, re := range config.Server.WebSockets.allowedOriginRegexps {
				if re.MatchString(origin) {
					return true
				}
			}
			return false
		},
	}

	conn, err := wsUpgrader.Upgrade(w, r, nil)
	if err != nil {
		wl.server.logger.Info("internal", "websocket upgrade error", wl.addr, err.Error())
		return
	}

	wConn, ok := conn.UnderlyingConn().(*utils.WrappedConn)
	if !ok {
		wl.server.logger.Error("internal", "non-proxied connection on websocket", wl.addr)
		conn.Close()
		return
	}

	confirmProxyData(wConn, remoteAddr, xff, xfp, config)

	// avoid a DoS attack from buffering excessively large messages:
	conn.SetReadLimit(maxReadQBytes)

	go wl.server.RunClient(NewIRCWSConn(conn))
}

// validate conn.ProxiedIP and conn.Secure against config, HTTP headers, etc.
func confirmProxyData(conn *utils.WrappedConn, remoteAddr, xForwardedFor, xForwardedProto string, config *Config) {
	if conn.ProxiedIP != nil {
		if !utils.IPInNets(utils.AddrToIP(conn.RemoteAddr()), config.Server.proxyAllowedFromNets) {
			conn.ProxiedIP = nil
		}
	} else if xForwardedFor != "" {
		proxiedIP := utils.HandleXForwardedFor(remoteAddr, xForwardedFor, config.Server.proxyAllowedFromNets)
		// don't set proxied IP if it is redundant with the actual IP
		if proxiedIP != nil && !proxiedIP.Equal(utils.AddrToIP(conn.RemoteAddr())) {
			conn.ProxiedIP = proxiedIP
		}
	}

	if conn.Config.TLSConfig != nil || conn.Config.Tor {
		// we terminated our own encryption:
		conn.Secure = true
	} else if !conn.Config.WebSocket {
		// plaintext normal connection: loopback and secureNets are secure
		realIP := utils.AddrToIP(conn.RemoteAddr())
		conn.Secure = realIP.IsLoopback() || utils.IPInNets(realIP, config.Server.secureNets)
	} else {
		// plaintext websocket: trust X-Forwarded-Proto from a trusted source
		conn.Secure = utils.IPInNets(utils.AddrToIP(conn.RemoteAddr()), config.Server.proxyAllowedFromNets) &&
			xForwardedProto == "https"
	}
}
<commit_msg>delete some unused fields<commit_after>// Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
// released under the MIT license

package irc

import (
	"errors"
	"net"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/gorilla/websocket"

	"github.com/oragono/oragono/irc/utils"
)

var (
	errCantReloadListener = errors.New("can't switch a listener between stream and websocket")
)

// IRCListener is an abstract wrapper for a listener (TCP port or unix domain socket).
// Server tracks these by listen address and can reload or stop them during rehash.
type IRCListener interface {
	Reload(config utils.ListenerConfig) error
	Stop() error
}

// NewListener creates a new listener according to the specifications in the config file
func NewListener(server *Server, addr string, config utils.ListenerConfig, bindMode os.FileMode) (result IRCListener, err error) {
	baseListener, err := createBaseListener(addr, bindMode)
	if err != nil {
		return
	}

	wrappedListener := utils.NewReloadableListener(baseListener, config)

	if config.WebSocket {
		return NewWSListener(server, addr, wrappedListener, config)
	} else {
		return NewNetListener(server, addr, wrappedListener, config)
	}
}

func createBaseListener(addr string, bindMode os.FileMode) (listener net.Listener, err error) {
	addr = strings.TrimPrefix(addr, "unix:")
	if strings.HasPrefix(addr, "/") {
		// https://stackoverflow.com/a/34881585
		os.Remove(addr)
		listener, err = net.Listen("unix", addr)
		if err == nil && bindMode != 0 {
			os.Chmod(addr, bindMode)
		}
	} else {
		listener, err = net.Listen("tcp", addr)
	}
	return
}

// NetListener is an IRCListener for a regular stream socket (TCP or unix domain)
type NetListener struct {
	listener *utils.ReloadableListener
	server   *Server
	addr     string
}

func NewNetListener(server *Server, addr string, listener *utils.ReloadableListener, config utils.ListenerConfig) (result *NetListener, err error) {
	nl := NetListener{
		server:   server,
		listener: listener,
		addr:     addr,
	}
	go nl.serve()
	return &nl, nil
}

func (nl *NetListener) Reload(config utils.ListenerConfig) error {
	if config.WebSocket {
		return errCantReloadListener
	}
	nl.listener.Reload(config)
	return nil
}

func (nl *NetListener) Stop() error {
	return nl.listener.Close()
}

func (nl *NetListener) serve() {
	for {
		conn, err := nl.listener.Accept()

		if err == nil {
			// hand off the connection
			wConn, ok := conn.(*utils.WrappedConn)
			if ok {
				confirmProxyData(wConn, "", "", "", nl.server.Config())
				go nl.server.RunClient(NewIRCStreamConn(wConn))
			} else {
				nl.server.logger.Error("internal", "invalid connection type", nl.addr)
			}
		} else if err == utils.ErrNetClosing {
			return
		} else {
			nl.server.logger.Error("internal", "accept error", nl.addr, err.Error())
		}
	}
}

// WSListener is a listener for IRC-over-websockets (initially HTTP, then upgraded to a
// different application protocol that provides a message-based API, possibly with TLS)
type WSListener struct {
	listener   *utils.ReloadableListener
	httpServer *http.Server
	server     *Server
	addr       string
}

func NewWSListener(server *Server, addr string, listener *utils.ReloadableListener, config utils.ListenerConfig) (result *WSListener, err error) {
	result = &WSListener{
		listener: listener,
		server:   server,
		addr:     addr,
	}
	result.httpServer = &http.Server{
		Handler:      http.HandlerFunc(result.handle),
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
	}
	go result.httpServer.Serve(listener)
	return
}

func (wl *WSListener) Reload(config utils.ListenerConfig) error {
	if !config.WebSocket {
		return errCantReloadListener
	}
	wl.listener.Reload(config)
	return nil
}

func (wl *WSListener) Stop() error {
	return wl.httpServer.Close()
}

func (wl *WSListener) handle(w http.ResponseWriter, r *http.Request) {
	config := wl.server.Config()
	remoteAddr := r.RemoteAddr
	xff := r.Header.Get("X-Forwarded-For")
	xfp := r.Header.Get("X-Forwarded-Proto")

	wsUpgrader := websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			if len(config.Server.WebSockets.allowedOriginRegexps) == 0 {
				return true
			}
			origin := strings.TrimSpace(r.Header.Get("Origin"))
			if len(origin) == 0 {
				return false
			}
			for _, re := range config.Server.WebSockets.allowedOriginRegexps {
				if re.MatchString(origin) {
					return true
				}
			}
			return false
		},
	}

	conn, err := wsUpgrader.Upgrade(w, r, nil)
	if err != nil {
		wl.server.logger.Info("internal", "websocket upgrade error", wl.addr, err.Error())
		return
	}

	wConn, ok := conn.UnderlyingConn().(*utils.WrappedConn)
	if !ok {
		wl.server.logger.Error("internal", "non-proxied connection on websocket", wl.addr)
		conn.Close()
		return
	}

	confirmProxyData(wConn, remoteAddr, xff, xfp, config)

	// avoid a DoS attack from buffering excessively large messages:
	conn.SetReadLimit(maxReadQBytes)

	go wl.server.RunClient(NewIRCWSConn(conn))
}

// validate conn.ProxiedIP and conn.Secure against config, HTTP headers, etc.
func confirmProxyData(conn *utils.WrappedConn, remoteAddr, xForwardedFor, xForwardedProto string, config *Config) {
	if conn.ProxiedIP != nil {
		if !utils.IPInNets(utils.AddrToIP(conn.RemoteAddr()), config.Server.proxyAllowedFromNets) {
			conn.ProxiedIP = nil
		}
	} else if xForwardedFor != "" {
		proxiedIP := utils.HandleXForwardedFor(remoteAddr, xForwardedFor, config.Server.proxyAllowedFromNets)
		// don't set proxied IP if it is redundant with the actual IP
		if proxiedIP != nil && !proxiedIP.Equal(utils.AddrToIP(conn.RemoteAddr())) {
			conn.ProxiedIP = proxiedIP
		}
	}

	if conn.Config.TLSConfig != nil || conn.Config.Tor {
		// we terminated our own encryption:
		conn.Secure = true
	} else if !conn.Config.WebSocket {
		// plaintext normal connection: loopback and secureNets are secure
		realIP := utils.AddrToIP(conn.RemoteAddr())
		conn.Secure = realIP.IsLoopback() || utils.IPInNets(realIP, config.Server.secureNets)
	} else {
		// plaintext websocket: trust X-Forwarded-Proto from a trusted source
		conn.Secure = utils.IPInNets(utils.AddrToIP(conn.RemoteAddr()), config.Server.proxyAllowedFromNets) &&
			xForwardedProto == "https"
	}
}
<|endoftext|>