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

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"

	// Imports so that goinstall automatically installs them.
	_ "code.google.com/p/go-tour/pic"
	_ "code.google.com/p/go-tour/tree"
	_ "code.google.com/p/go-tour/wc"
)

const basePkg = "code.google.com/p/go-tour/"

var (
	httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput = flag.Bool("html", false, "render program output as HTML")
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)
)

func main() {
	flag.Parse()

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	// find and serve the go tour files
	p, err := build.Default.Import(basePkg, "", build.FindOnly)
	if err != nil {
		log.Fatalf("Couldn't find tour files: %v", err)
	}
	root := p.Dir
	log.Println("Serving content from", root)
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/favicon.ico" || r.URL.Path == "/" {
			fn := filepath.Join(root, "static", r.URL.Path[1:])
			http.ServeFile(w, r, fn)
			return
		}
		http.Error(w, "not found", 404)
	})
	http.Handle("/static/", http.FileServer(http.Dir(root)))
	http.HandleFunc("/kill", kill)

	if !strings.HasPrefix(*httpListen, "127.0.0.1") &&
		!strings.HasPrefix(*httpListen, "localhost") {
		log.Print(localhostWarning)
	}

	log.Printf("Serving at http://%s/", *httpListen)
	log.Fatal(http.ListenAndServe(*httpListen, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

var running struct {
	sync.Mutex
	cmd *exec.Cmd
}

func stopRun() {
	running.Lock()
	if running.cmd != nil {
		running.cmd.Process.Kill()
		running.cmd = nil
	}
	running.Unlock()
}

func kill(w http.ResponseWriter, r *http.Request) {
	stopRun()
}

var (
	commentRe = regexp.MustCompile(`(?m)^#.*\n`)
	tmpdir    string
)

func init() {
	// find real temporary directory (for rewriting filename in output)
	var err error
	tmpdir, err = filepath.EvalSymlinks(os.TempDir())
	if err != nil {
		log.Fatal(err)
	}
}

func compile(req *http.Request) (out []byte, err error) {
	stopRun()

	// x is the base name for .go, .6, executable files
	x := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
	src := x + ".go"
	bin := x
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// rewrite filename in error output
	defer func() {
		if err != nil {
			// drop messages from the go tool like '# _/compile0'
			out = commentRe.ReplaceAll(out, nil)
		}
		out = bytes.Replace(out, []byte(src+":"), []byte("main.go:"), -1)
	}()

	// write body to x.go
	body := []byte(req.FormValue("body"))
	defer os.Remove(src)
	if err = ioutil.WriteFile(src, body, 0666); err != nil {
		return
	}

	// build x.go, creating x
	dir, file := filepath.Split(src)
	out, err = run(dir, "go", "build", "-o", bin, file)
	defer os.Remove(bin)
	if err != nil {
		return
	}

	// run x
	return run("", bin)
}

// run executes the specified command and returns its output and an error.
func run(dir string, args ...string) ([]byte, error) {
	var buf bytes.Buffer
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir
	cmd.Stdout = &buf
	cmd.Stderr = cmd.Stdout

	// Start command and leave in 'running'.
	running.Lock()
	if running.cmd != nil {
		defer running.Unlock()
		return nil, fmt.Errorf("already running %s", running.cmd.Path)
	}
	if err := cmd.Start(); err != nil {
		running.Unlock()
		return nil, err
	}
	running.cmd = cmd
	running.Unlock()

	// Wait for the command.  Clean up,
	err := cmd.Wait()
	running.Lock()
	if running.cmd == cmd {
		running.cmd = nil
	}
	running.Unlock()
	return buf.Bytes(), err
}
<commit_msg>gotour: make the console messages more descriptive<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"

	// Imports so that goinstall automatically installs them.
	_ "code.google.com/p/go-tour/pic"
	_ "code.google.com/p/go-tour/tree"
	_ "code.google.com/p/go-tour/wc"
)

const basePkg = "code.google.com/p/go-tour/"

var (
	httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput = flag.Bool("html", false, "render program output as HTML")
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)
)

func main() {
	flag.Parse()

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	// find and serve the go tour files
	p, err := build.Default.Import(basePkg, "", build.FindOnly)
	if err != nil {
		log.Fatalf("Couldn't find tour files: %v", err)
	}
	root := p.Dir
	log.Println("Serving content from", root)
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/favicon.ico" || r.URL.Path == "/" {
			fn := filepath.Join(root, "static", r.URL.Path[1:])
			http.ServeFile(w, r, fn)
			return
		}
		http.Error(w, "not found", 404)
	})
	http.Handle("/static/", http.FileServer(http.Dir(root)))
	http.HandleFunc("/kill", kill)

	if !strings.HasPrefix(*httpListen, "127.0.0.1") &&
		!strings.HasPrefix(*httpListen, "localhost") {
		log.Print(localhostWarning)
	}

	log.Printf("Open your web browser and visit http://%s/", *httpListen)
	log.Fatal(http.ListenAndServe(*httpListen, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

var running struct {
	sync.Mutex
	cmd *exec.Cmd
}

func stopRun() {
	running.Lock()
	if running.cmd != nil {
		running.cmd.Process.Kill()
		running.cmd = nil
	}
	running.Unlock()
}

func kill(w http.ResponseWriter, r *http.Request) {
	stopRun()
}

var (
	commentRe = regexp.MustCompile(`(?m)^#.*\n`)
	tmpdir    string
)

func init() {
	// find real temporary directory (for rewriting filename in output)
	var err error
	tmpdir, err = filepath.EvalSymlinks(os.TempDir())
	if err != nil {
		log.Fatal(err)
	}
}

func compile(req *http.Request) (out []byte, err error) {
	stopRun()

	// x is the base name for .go, .6, executable files
	x := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
	src := x + ".go"
	bin := x
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// rewrite filename in error output
	defer func() {
		if err != nil {
			// drop messages from the go tool like '# _/compile0'
			out = commentRe.ReplaceAll(out, nil)
		}
		out = bytes.Replace(out, []byte(src+":"), []byte("main.go:"), -1)
	}()

	// write body to x.go
	body := []byte(req.FormValue("body"))
	defer os.Remove(src)
	if err = ioutil.WriteFile(src, body, 0666); err != nil {
		return
	}

	// build x.go, creating x
	dir, file := filepath.Split(src)
	out, err = run(dir, "go", "build", "-o", bin, file)
	defer os.Remove(bin)
	if err != nil {
		return
	}

	// run x
	return run("", bin)
}

// run executes the specified command and returns its output and an error.
func run(dir string, args ...string) ([]byte, error) {
	var buf bytes.Buffer
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir
	cmd.Stdout = &buf
	cmd.Stderr = cmd.Stdout

	// Start command and leave in 'running'.
	running.Lock()
	if running.cmd != nil {
		defer running.Unlock()
		return nil, fmt.Errorf("already running %s", running.cmd.Path)
	}
	if err := cmd.Start(); err != nil {
		running.Unlock()
		return nil, err
	}
	running.cmd = cmd
	running.Unlock()

	// Wait for the command.  Clean up,
	err := cmd.Wait()
	running.Lock()
	if running.cmd == cmd {
		running.cmd = nil
	}
	running.Unlock()
	return buf.Bytes(), err
}
<|endoftext|>


<commit_before>// Copyright 2015 Dmitry Vyukov. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package gotypes

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/format"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"golang.org/x/tools/go/ssa"
)

// https://github.com/golang/go/issues/11327
var bigNum = regexp.MustCompile("(\\.[0-9]*)|([0-9]+)[eE]\\-?\\+?[0-9]{3,}")
var bigNum2 = regexp.MustCompile("[0-9]+[pP][0-9]{3,}") // see issue 11364

// https://github.com/golang/go/issues/11274
var formatBug1 = regexp.MustCompile("\\*/[ \t\n\r\f\v]*;")
var formatBug2 = regexp.MustCompile(";[ \t\n\r\f\v]*/\\*")

var issue11590 = regexp.MustCompile(": cannot convert .* \\(untyped int constant .*\\) to complex")
var issue11590_2 = regexp.MustCompile(": [0-9]+ (untyped int constant) overflows complex")
var issue11370 = regexp.MustCompile("\\\"[ \t\n\r\f\v]*\\[")

var fpRounding = regexp.MustCompile(" \\(untyped float constant .*\\) truncated to ")
var something = regexp.MustCompile(" constant .* overflows ")

var gcCrash = regexp.MustCompile("\n/tmp/fuzz\\.gc[0-9]+:[0-9]+: internal compiler error: ")
var asanCrash = regexp.MustCompile("\n==[0-9]+==ERROR: AddressSanitizer: ")

func Fuzz(data []byte) int {
	if bigNum.Match(data) || bigNum2.Match(data) {
		return 0
	}
	goErr := gotypes(data)
	gcErr := gc(data)
	gccgoErr := gccgo(data)
	if goErr == nil && gcErr != nil {
		if strings.Contains(gcErr.Error(), "line number out of range") {
			// https://github.com/golang/go/issues/11329
			return 0
		}
		if strings.Contains(gcErr.Error(), "overflow in int -> string") {
			// https://github.com/golang/go/issues/11330
			return 0
		}
		if strings.Contains(gcErr.Error(), "larger than address space") {
			// Gc is more picky at rejecting huge objects.
			return 0
		}
		if strings.Contains(gcErr.Error(), "non-canonical import path") {
			return 0
		}
		if strings.Contains(gcErr.Error(), "constant shift overflow") {
			// ???
			return 0
		}
		if something.MatchString(gcErr.Error()) {
			// ???
			return 0
		}
	}

	if gcErr == nil && goErr != nil {
		if strings.Contains(goErr.Error(), "illegal character U+") {
			// https://github.com/golang/go/issues/11359
			return 0
		}
		if issue11590.MatchString(goErr.Error()) || issue11590_2.MatchString(goErr.Error()) {
			// https://github.com/golang/go/issues/11590
			return 0
		}
		if issue11370.MatchString(goErr.Error()) {
			return 0
		}
	}

	if gccgoErr == nil && goErr != nil {
		if strings.Contains(goErr.Error(), "invalid operation: stupid shift count") {
			// https://github.com/golang/go/issues/11524
			return 0
		}
		if (bytes.Contains(data, []byte("//line")) || bytes.Contains(data, []byte("/*"))) &&
			(strings.Contains(goErr.Error(), "illegal UTF-8 encoding") ||
				strings.Contains(goErr.Error(), "illegal character NUL")) {
			// https://github.com/golang/go/issues/11527
			return 0
		}
		if fpRounding.MatchString(goErr.Error()) {
			// gccgo has different rounding
			return 0
		}
		if strings.Contains(goErr.Error(), "operator | not defined for") {
			// https://github.com/golang/go/issues/11566
			return 0
		}
		if strings.Contains(goErr.Error(), "illegal byte order mark") {
			// on "package\rG\n//line \ufeff:1" input, not filed.
			return 0
		}
	}

	if goErr == nil && gccgoErr != nil {
		if strings.Contains(gccgoErr.Error(), "error: integer constant overflow") {
			// https://github.com/golang/go/issues/11525
			return 0
		}
		if bytes.Contains(data, []byte("0i")) &&
			(strings.Contains(gccgoErr.Error(), "incompatible types in binary expression") ||
				strings.Contains(gccgoErr.Error(), "initialization expression has wrong type")) {
			// https://github.com/golang/go/issues/11564
			// https://github.com/golang/go/issues/11563
			return 0
		}
	}

	// go-fuzz is too smart so it can generate a program that contains "internal compiler error" in an error message :)
	if gcErr != nil && (gcCrash.MatchString(gcErr.Error()) ||
		strings.Contains(gcErr.Error(), "\nruntime error: ") ||
		strings.HasPrefix(gcErr.Error(), "runtime error: ") ||
		strings.Contains(gcErr.Error(), "%!")) { // bad format string
		if strings.Contains(gcErr.Error(), "internal compiler error: out of fixed registers") {
			// https://github.com/golang/go/issues/11352
			return 0
		}
		if strings.Contains(gcErr.Error(), "internal compiler error: treecopy Name") {
			// https://github.com/golang/go/issues/11361
			return 0
		}
		if strings.Contains(gcErr.Error(), "internal compiler error: newname nil") {
			// https://github.com/golang/go/issues/11610
			return 0
		}
		fmt.Printf("gc result: %v\n", gcErr)
		panic("gc compiler crashed")
	}

	const gccgoCrash = "go1: internal compiler error:"
	if gccgoErr != nil && (strings.HasPrefix(gccgoErr.Error(), gccgoCrash) || strings.Contains(gccgoErr.Error(), "\n"+gccgoCrash)) {
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in check_bounds, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/11545
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in do_export, at go/gofrontend/types.cc") {
			// https://github.com/golang/go/issues/12321
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in do_lower, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/12615
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in insert, at go/gofrontend/gogo.cc") {
			// https://github.com/golang/go/issues/12616
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in wide_int_to_tree, at tree.c") {
			// https://github.com/golang/go/issues/12618
			return 0
		}
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gccgo compiler crashed")
	}

	if gccgoErr != nil && asanCrash.MatchString(gccgoErr.Error()) {
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gccgo compiler crashed")
	}

	if gcErr == nil && goErr == nil && gccgoErr != nil && strings.Contains(gccgoErr.Error(), "0x124a4") {
		// https://github.com/golang/go/issues/12322
		return 0
	}

	if (goErr == nil) != (gcErr == nil) || (goErr == nil) != (gccgoErr == nil) {
		fmt.Printf("go/types result: %v\n", goErr)
		fmt.Printf("gc result: %v\n", gcErr)
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gc, gccgo and go/types disagree")
	}
	if goErr != nil {
		return 0

	}
	if formatBug1.Match(data) || formatBug2.Match(data) {
		return 1
	}
	// https://github.com/golang/go/issues/11274
	data = bytes.Replace(data, []byte{'\r'}, []byte{' '}, -1)
	data1, err := format.Source(data)
	if err != nil {
		panic(err)
	}
	if false {
		err = gotypes(data1)
		if err != nil {
			fmt.Printf("new: %q\n", data1)
			fmt.Printf("err: %v\n", err)
			panic("program become invalid after gofmt")
		}
	}
	return 1
}

func gotypes(data []byte) (err error) {
	fset := token.NewFileSet()
	var f *ast.File
	f, err = parser.ParseFile(fset, "src.go", data, parser.ParseComments|parser.DeclarationErrors|parser.AllErrors)
	if err != nil {
		return
	}
	// provide error handler
	// initialize maps in config
	conf := &types.Config{
		Error:    func(err error) {},
		Sizes:    &types.StdSizes{8, 8},
		Importer: importer.For("gc", nil),
	}
	_, err = conf.Check("pkg", fset, []*ast.File{f}, nil)
	if err != nil {
		return
	}
	prog := ssa.NewProgram(fset, ssa.BuildSerially|ssa.SanityCheckFunctions|ssa.GlobalDebug)
	prog.BuildAll()
	for _, pkg := range prog.AllPackages() {
		_, err := pkg.WriteTo(ioutil.Discard)
		if err != nil {
			panic(err)
		}
	}
	return
}

func gc(data []byte) error {
	f, err := ioutil.TempFile("", "fuzz.gc")
	if err != nil {
		return err
	}
	defer os.Remove(f.Name())
	defer f.Close()
	_, err = f.Write(data)
	if err != nil {
		return err
	}
	f.Close()
	out, err := exec.Command("compile", f.Name()).CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s\n%s", out, err)
	}
	return nil
}

func gccgo(data []byte) error {
	cmd := exec.Command("gccgo", "-c", "-x", "go", "-O3", "-o", "/dev/null", "-")
	cmd.Stdin = bytes.NewReader(data)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s\n%s", out, err)
	}
	return nil
}
<commit_msg>Update main.go<commit_after>// Copyright 2015 Dmitry Vyukov. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package gotypes

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/format"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"golang.org/x/tools/go/ssa"
)

// https://github.com/golang/go/issues/11327
var bigNum = regexp.MustCompile("(\\.[0-9]*)|([0-9]+)[eE]\\-?\\+?[0-9]{3,}")
var bigNum2 = regexp.MustCompile("[0-9]+[pP][0-9]{3,}") // see issue 11364

// https://github.com/golang/go/issues/11274
var formatBug1 = regexp.MustCompile("\\*/[ \t\n\r\f\v]*;")
var formatBug2 = regexp.MustCompile(";[ \t\n\r\f\v]*/\\*")

var issue11590 = regexp.MustCompile(": cannot convert .* \\(untyped int constant .*\\) to complex")
var issue11590_2 = regexp.MustCompile(": [0-9]+ (untyped int constant) overflows complex")
var issue11370 = regexp.MustCompile("\\\"[ \t\n\r\f\v]*\\[")

var fpRounding = regexp.MustCompile(" \\(untyped float constant .*\\) truncated to ")
var something = regexp.MustCompile(" constant .* overflows ")

var gcCrash = regexp.MustCompile("\n/tmp/fuzz\\.gc[0-9]+:[0-9]+: internal compiler error: ")
var asanCrash = regexp.MustCompile("\n==[0-9]+==ERROR: AddressSanitizer: ")

func Fuzz(data []byte) int {
	if bigNum.Match(data) || bigNum2.Match(data) {
		return 0
	}
	goErr := gotypes(data)
	gcErr := gc(data)
	gccgoErr := gccgo(data)
	if goErr == nil && gcErr != nil {
		if strings.Contains(gcErr.Error(), "line number out of range") {
			// https://github.com/golang/go/issues/11329
			return 0
		}
		if strings.Contains(gcErr.Error(), "overflow in int -> string") {
			// https://github.com/golang/go/issues/11330
			return 0
		}
		if strings.Contains(gcErr.Error(), "larger than address space") {
			// Gc is more picky at rejecting huge objects.
			return 0
		}
		if strings.Contains(gcErr.Error(), "non-canonical import path") {
			return 0
		}
		if strings.Contains(gcErr.Error(), "constant shift overflow") {
			// ???
			return 0
		}
		if something.MatchString(gcErr.Error()) {
			// ???
			return 0
		}
	}

	if gcErr == nil && goErr != nil {
		if strings.Contains(goErr.Error(), "illegal character U+") {
			// https://github.com/golang/go/issues/11359
			return 0
		}
		if issue11590.MatchString(goErr.Error()) || issue11590_2.MatchString(goErr.Error()) {
			// https://github.com/golang/go/issues/11590
			return 0
		}
		if issue11370.MatchString(goErr.Error()) {
			return 0
		}
	}

	if gccgoErr == nil && goErr != nil {
		if strings.Contains(goErr.Error(), "invalid operation: stupid shift count") {
			// https://github.com/golang/go/issues/11524
			return 0
		}
		if (bytes.Contains(data, []byte("//line")) || bytes.Contains(data, []byte("/*"))) &&
			(strings.Contains(goErr.Error(), "illegal UTF-8 encoding") ||
				strings.Contains(goErr.Error(), "illegal character NUL")) {
			// https://github.com/golang/go/issues/11527
			return 0
		}
		if fpRounding.MatchString(goErr.Error()) {
			// gccgo has different rounding
			return 0
		}
		if strings.Contains(goErr.Error(), "operator | not defined for") {
			// https://github.com/golang/go/issues/11566
			return 0
		}
		if strings.Contains(goErr.Error(), "illegal byte order mark") {
			// on "package\rG\n//line \ufeff:1" input, not filed.
			return 0
		}
	}

	if goErr == nil && gccgoErr != nil {
		if strings.Contains(gccgoErr.Error(), "error: integer constant overflow") {
			// https://github.com/golang/go/issues/11525
			return 0
		}
		if bytes.Contains(data, []byte("0i")) &&
			(strings.Contains(gccgoErr.Error(), "incompatible types in binary expression") ||
				strings.Contains(gccgoErr.Error(), "initialization expression has wrong type")) {
			// https://github.com/golang/go/issues/11564
			// https://github.com/golang/go/issues/11563
			return 0
		}
	}

	// go-fuzz is too smart so it can generate a program that contains "internal compiler error" in an error message :)
	if gcErr != nil && (gcCrash.MatchString(gcErr.Error()) ||
		strings.Contains(gcErr.Error(), "\nruntime error: ") ||
		strings.HasPrefix(gcErr.Error(), "runtime error: ") ||
		strings.Contains(gcErr.Error(), "%!")) { // bad format string
		if strings.Contains(gcErr.Error(), "internal compiler error: out of fixed registers") {
			// https://github.com/golang/go/issues/11352
			return 0
		}
		if strings.Contains(gcErr.Error(), "internal compiler error: treecopy Name") {
			// https://github.com/golang/go/issues/11361
			return 0
		}
		if strings.Contains(gcErr.Error(), "internal compiler error: newname nil") {
			// https://github.com/golang/go/issues/11610
			return 0
		}
		fmt.Printf("gc result: %v\n", gcErr)
		panic("gc compiler crashed")
	}

	const gccgoCrash = "go1: internal compiler error:"
	if gccgoErr != nil && (strings.HasPrefix(gccgoErr.Error(), gccgoCrash) || strings.Contains(gccgoErr.Error(), "\n"+gccgoCrash)) {
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in do_export, at go/gofrontend/types.cc") {
			// https://github.com/golang/go/issues/12321
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in do_lower, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/12615
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in insert, at go/gofrontend/gogo.cc") {
			// https://github.com/golang/go/issues/12616
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in wide_int_to_tree, at tree.c") {
			// https://github.com/golang/go/issues/12618
			return 0
		}
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gccgo compiler crashed")
	}

	if gccgoErr != nil && asanCrash.MatchString(gccgoErr.Error()) {
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gccgo compiler crashed")
	}

	if gcErr == nil && goErr == nil && gccgoErr != nil && strings.Contains(gccgoErr.Error(), "0x124a4") {
		// https://github.com/golang/go/issues/12322
		return 0
	}

	if (goErr == nil) != (gcErr == nil) || (goErr == nil) != (gccgoErr == nil) {
		fmt.Printf("go/types result: %v\n", goErr)
		fmt.Printf("gc result: %v\n", gcErr)
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gc, gccgo and go/types disagree")
	}
	if goErr != nil {
		return 0

	}
	if formatBug1.Match(data) || formatBug2.Match(data) {
		return 1
	}
	// https://github.com/golang/go/issues/11274
	data = bytes.Replace(data, []byte{'\r'}, []byte{' '}, -1)
	data1, err := format.Source(data)
	if err != nil {
		panic(err)
	}
	if false {
		err = gotypes(data1)
		if err != nil {
			fmt.Printf("new: %q\n", data1)
			fmt.Printf("err: %v\n", err)
			panic("program become invalid after gofmt")
		}
	}
	return 1
}

func gotypes(data []byte) (err error) {
	fset := token.NewFileSet()
	var f *ast.File
	f, err = parser.ParseFile(fset, "src.go", data, parser.ParseComments|parser.DeclarationErrors|parser.AllErrors)
	if err != nil {
		return
	}
	// provide error handler
	// initialize maps in config
	conf := &types.Config{
		Error:    func(err error) {},
		Sizes:    &types.StdSizes{8, 8},
		Importer: importer.For("gc", nil),
	}
	_, err = conf.Check("pkg", fset, []*ast.File{f}, nil)
	if err != nil {
		return
	}
	prog := ssa.NewProgram(fset, ssa.BuildSerially|ssa.SanityCheckFunctions|ssa.GlobalDebug)
	prog.BuildAll()
	for _, pkg := range prog.AllPackages() {
		_, err := pkg.WriteTo(ioutil.Discard)
		if err != nil {
			panic(err)
		}
	}
	return
}

func gc(data []byte) error {
	f, err := ioutil.TempFile("", "fuzz.gc")
	if err != nil {
		return err
	}
	defer os.Remove(f.Name())
	defer f.Close()
	_, err = f.Write(data)
	if err != nil {
		return err
	}
	f.Close()
	out, err := exec.Command("compile", f.Name()).CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s\n%s", out, err)
	}
	return nil
}

func gccgo(data []byte) error {
	cmd := exec.Command("gccgo", "-c", "-x", "go", "-O3", "-o", "/dev/null", "-")
	cmd.Stdin = bytes.NewReader(data)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s\n%s", out, err)
	}
	return nil
}
<|endoftext|>


<commit_before>package gitlab

import (
	"fmt"
	"net/url"
)

// GroupLabelsService handles communication with the label related methods of the
// GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/group_labels.html
type GroupLabelsService struct {
	client *Client
}

// GroupLabel represents a GitLab group label.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/group_labels.html
type GroupLabel Label

func (l GroupLabel) String() string {
	return Stringify(l)
}

// ListGroupLabelsOptions represents the available ListGroupLabels() options.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels
type ListGroupLabelsOptions ListOptions

// ListGroupLabels gets all labels for given group.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/group_labels.html#list-group-labels
func (s *GroupLabelsService) ListGroupLabels(gid interface{}, opt *ListGroupLabelsOptions, options ...OptionFunc) ([]*GroupLabel, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/labels", url.QueryEscape(group))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var l []*GroupLabel
	resp, err := s.client.Do(req, &l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// CreateGroupLabelOptions represents the available CreateGroupLabel() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#create-a-new-group-label
type CreateGroupLabelOptions CreateLabelOptions

// CreateGroupLabel creates a new label for given group with given name and
// color.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#create-a-new-group-label
func (s *GroupLabelsService) CreateGroupLabel(gid interface{}, opt *CreateGroupLabelOptions, options ...OptionFunc) (*GroupLabel, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/labels", url.QueryEscape(group))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(GroupLabel)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// DeleteGroupLabelOptions represents the available DeleteGroupLabel() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#delete-a-group-label
type DeleteGroupLabelOptions DeleteLabelOptions

// DeleteGroupLabel deletes a group label given by its name.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
func (s *GroupLabelsService) DeleteGroupLabel(gid interface{}, opt *DeleteGroupLabelOptions, options ...OptionFunc) (*Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("groups/%s/labels", url.QueryEscape(group))

	req, err := s.client.NewRequest("DELETE", u, opt, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}

// UpdateGroupLabelOptions represents the available UpdateGroupLabel() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#update-a-group-label
type UpdateGroupLabelOptions UpdateLabelOptions

// UpdateGroupLabel updates an existing label with new name or now color. At least
// one parameter is required, to update the label.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#update-a-group-label
func (s *GroupLabelsService) UpdateGroupLabel(gid interface{}, opt *UpdateGroupLabelOptions, options ...OptionFunc) (*GroupLabel, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/labels", url.QueryEscape(group))

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(GroupLabel)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// SubscribeToGroupLabel subscribes the authenticated user to a label to receive
// notifications. If the user is already subscribed to the label, the status
// code 304 is returned.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#subscribe-to-a-group-label
func (s *GroupLabelsService) SubscribeToGroupLabel(gid interface{}, labelID interface{}, options ...OptionFunc) (*GroupLabel, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	label, err := parseID(labelID)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/labels/%s/subscribe", url.QueryEscape(group), label)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(GroupLabel)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// UnsubscribeFromGroupLabel unsubscribes the authenticated user from a label to not
// receive notifications from it. If the user is not subscribed to the label, the
// status code 304 is returned.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#unsubscribe-from-a-group-label
func (s *GroupLabelsService) UnsubscribeFromGroupLabel(gid interface{}, labelID interface{}, options ...OptionFunc) (*Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, err
	}
	label, err := parseID(labelID)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("groups/%s/labels/%s/unsubscribe", url.QueryEscape(group), label)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<commit_msg>Update group_labels.go<commit_after>package gitlab

import (
	"fmt"
	"net/url"
)

// GroupLabelsService handles communication with the label related methods of the
// GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/group_labels.html
type GroupLabelsService struct {
	client *Client
}

// GroupLabel represents a GitLab group label.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/group_labels.html
type GroupLabel Label

func (l GroupLabel) String() string {
	return Stringify(l)
}

// ListGroupLabelsOptions represents the available ListGroupLabels() options.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels
type ListGroupLabelsOptions ListOptions

// ListGroupLabels gets all labels for given group.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#list-group-labels
func (s *GroupLabelsService) ListGroupLabels(gid interface{}, opt *ListGroupLabelsOptions, options ...OptionFunc) ([]*GroupLabel, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/labels", url.QueryEscape(group))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var l []*GroupLabel
	resp, err := s.client.Do(req, &l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// CreateGroupLabelOptions represents the available CreateGroupLabel() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#create-a-new-group-label
type CreateGroupLabelOptions CreateLabelOptions

// CreateGroupLabel creates a new label for given group with given name and
// color.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#create-a-new-group-label
func (s *GroupLabelsService) CreateGroupLabel(gid interface{}, opt *CreateGroupLabelOptions, options ...OptionFunc) (*GroupLabel, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/labels", url.QueryEscape(group))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(GroupLabel)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// DeleteGroupLabelOptions represents the available DeleteGroupLabel() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#delete-a-group-label
type DeleteGroupLabelOptions DeleteLabelOptions

// DeleteGroupLabel deletes a group label given by its name.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label
func (s *GroupLabelsService) DeleteGroupLabel(gid interface{}, opt *DeleteGroupLabelOptions, options ...OptionFunc) (*Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("groups/%s/labels", url.QueryEscape(group))

	req, err := s.client.NewRequest("DELETE", u, opt, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}

// UpdateGroupLabelOptions represents the available UpdateGroupLabel() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#update-a-group-label
type UpdateGroupLabelOptions UpdateLabelOptions

// UpdateGroupLabel updates an existing label with new name or now color. At least
// one parameter is required, to update the label.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#update-a-group-label
func (s *GroupLabelsService) UpdateGroupLabel(gid interface{}, opt *UpdateGroupLabelOptions, options ...OptionFunc) (*GroupLabel, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/labels", url.QueryEscape(group))

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(GroupLabel)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// SubscribeToGroupLabel subscribes the authenticated user to a label to receive
// notifications. If the user is already subscribed to the label, the status
// code 304 is returned.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#subscribe-to-a-group-label
func (s *GroupLabelsService) SubscribeToGroupLabel(gid interface{}, labelID interface{}, options ...OptionFunc) (*GroupLabel, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	label, err := parseID(labelID)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/labels/%s/subscribe", url.QueryEscape(group), label)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(GroupLabel)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// UnsubscribeFromGroupLabel unsubscribes the authenticated user from a label to not
// receive notifications from it. If the user is not subscribed to the label, the
// status code 304 is returned.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/group_labels.html#unsubscribe-from-a-group-label
func (s *GroupLabelsService) UnsubscribeFromGroupLabel(gid interface{}, labelID interface{}, options ...OptionFunc) (*Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, err
	}
	label, err := parseID(labelID)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("groups/%s/labels/%s/unsubscribe", url.QueryEscape(group), label)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<|endoftext|>


<commit_before>package mcstore

import (
	"net/http"
	"path/filepath"

	"github.com/materials-commons/mcstore/pkg/app"
	"github.com/materials-commons/mcstore/pkg/db/schema"
	"github.com/materials-commons/mcstore/pkg/domain"
	"github.com/materials-commons/mcstore/pkg/ws"
)

// dataHandler implements the http.Handler interface. It provides an interface
// to serving up data stored in materials commons.
type dataHandler struct {
	access domain.Access
}

// NewDataHandler creates a new instance of a dataHandler.
func NewDataHandler(access domain.Access) http.Handler {
	return &dataHandler{
		access: access,
	}
}

// ServeHTTP serves data stored in materials commons.
func (h *dataHandler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
	path, mediaType, err := h.serveData(writer, req)
	switch {
	case err != nil:
		ws.WriteError(err, writer)
	default:
		serveFile(writer, req, path, mediaType)
	}
}

// serveFile serves up the actual file contents. It sets the content-type header to
// the mediatype specified. If the file doesn't exist, or the server doesn't have
// permissions to access the file then a 404 (not found) will be returned by the
// http.ServeFile method.
func serveFile(writer http.ResponseWriter, req *http.Request, path, mediatype string) {
	writer.Header().Add("Content-Type", mediatype)
	if mediatype == "application/pdf" {
		writer.Header().Add("Content-Disposition", `inline; filename="filename.pdf"`)
	}
	app.Log.Debugf("Set Content-Type to %s", mediatype)
	http.ServeFile(writer, req, path)
}

// serveData does the actual work of serving the data. It checks the access on each
// request. It will also serve up converted images unless the original flag has been
// specified. The assumption is that without the original flag we are actually trying
// to render an image in a browser. Since browsers do not render all image types we
// convert some types to jpg files. This routine will serve up these jpg conversions
// rather than the original file unless the original flag is specified.
func (h *dataHandler) serveData(writer http.ResponseWriter, req *http.Request) (path string, mediatype string, err error) {
	// All requests require an apikey.
	apikey := req.FormValue("apikey")
	if apikey == "" {
		return path, mediatype, app.ErrNoAccess
	}
	app.Log.Debugf("serveData - Request for apikey %s", apikey)

	// Is the original data requested, or can we serve the converted
	// image data (if it exists)?
	original := getOriginalFormValue(req)
	app.Log.Debugf("serveData - Original flag %t", original)

	fileID := filepath.Base(req.URL.Path)
	app.Log.Debugf("serveData - fileID %s, URL %s", fileID, req.URL.Path)

	// Get the file, checking its access.
	file, err := h.access.GetFile(apikey, fileID)
	if err != nil {
		return path, mediatype, err
	}

	path = filePath(file, original)
	app.Log.Debugf("serveData - Serving path: %s\n", path)

	mediatype = file.MediaType.Mime

	// The content type is dependent on whether we are
	// serving the original or the converted file.
	if !original && isConvertedImage(file.MediaType.Mime) {
		mediatype = "image/jpeg"
	} else if !original && isExcelSpreadsheet(file.MediaType.Mime) {
		mediatype = "application/pdf"
	}

	return path, mediatype, nil
}

// getOriginalFormValue looks for the original argument on the URL. If it exists
// (has a value specified) then return true. The original flag specifies whether
// the user wants the original rather than the converted data.
func getOriginalFormValue(req *http.Request) bool {
	if req.FormValue("original") == "" {
		return false
	}
	return true
}

// filePath determines which file to serve. If there is a converted image we
// will serve that one up unless the original flag is set to true.
func filePath(file *schema.File, original bool) string {
	switch {
	case isConvertedImage(file.MediaType.Mime) && !original:
		return app.MCDir.FilePathImageConversion(file.FileID())
	case isExcelSpreadsheet(file.MediaType.Mime) && !original:
		return app.MCDir.FilePathFromConversionToPDF(file.FileID())
	default:
		return app.MCDir.FilePath(file.FileID())
	}
}

// isConvertedImage checks a name to see if it is an image type we have converted.
func isConvertedImage(mime string) bool {
	switch mime {
	case "image/tiff":
		return true
	case "image/x-ms-bmp":
		return true
	case "image/bmp":
		return true
	default:
		return false
	}
}

// isExcelSpreadsheet checks the mime type to see if it is an excel spreadsheet
func isExcelSpreadsheet(mime string) bool {
	switch mime {
	case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
		return true
	case "application/vnd.MS-Excel":
		return true
	default:
		return false
	}
}
<commit_msg>Serve PDF for any office files<commit_after>package mcstore

import (
	"net/http"
	"path/filepath"

	"github.com/materials-commons/mcstore/pkg/app"
	"github.com/materials-commons/mcstore/pkg/db/schema"
	"github.com/materials-commons/mcstore/pkg/domain"
	"github.com/materials-commons/mcstore/pkg/ws"
	"github.com/materials-commons/mcstore/pkg/files"
)

// dataHandler implements the http.Handler interface. It provides an interface
// to serving up data stored in materials commons.
type dataHandler struct {
	access domain.Access
}

// NewDataHandler creates a new instance of a dataHandler.
func NewDataHandler(access domain.Access) http.Handler {
	return &dataHandler{
		access: access,
	}
}

// ServeHTTP serves data stored in materials commons.
func (h *dataHandler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
	path, mediaType, err := h.serveData(writer, req)
	switch {
	case err != nil:
		ws.WriteError(err, writer)
	default:
		serveFile(writer, req, path, mediaType)
	}
}

// serveFile serves up the actual file contents. It sets the content-type header to
// the mediatype specified. If the file doesn't exist, or the server doesn't have
// permissions to access the file then a 404 (not found) will be returned by the
// http.ServeFile method.
func serveFile(writer http.ResponseWriter, req *http.Request, path, mediatype string) {
	writer.Header().Add("Content-Type", mediatype)
	if mediatype == "application/pdf" {
		writer.Header().Add("Content-Disposition", `inline; filename="filename.pdf"`)
	}
	app.Log.Debugf("Set Content-Type to %s", mediatype)
	http.ServeFile(writer, req, path)
}

// serveData does the actual work of serving the data. It checks the access on each
// request. It will also serve up converted images unless the original flag has been
// specified. The assumption is that without the original flag we are actually trying
// to render an image in a browser. Since browsers do not render all image types we
// convert some types to jpg files. This routine will serve up these jpg conversions
// rather than the original file unless the original flag is specified.
func (h *dataHandler) serveData(writer http.ResponseWriter, req *http.Request) (path string, mediatype string, err error) {
	// All requests require an apikey.
	apikey := req.FormValue("apikey")
	if apikey == "" {
		return path, mediatype, app.ErrNoAccess
	}
	app.Log.Debugf("serveData - Request for apikey %s", apikey)

	// Is the original data requested, or can we serve the converted
	// image data (if it exists)?
	original := getOriginalFormValue(req)
	app.Log.Debugf("serveData - Original flag %t", original)

	fileID := filepath.Base(req.URL.Path)
	app.Log.Debugf("serveData - fileID %s, URL %s", fileID, req.URL.Path)

	// Get the file, checking its access.
	file, err := h.access.GetFile(apikey, fileID)
	if err != nil {
		return path, mediatype, err
	}

	path = filePath(file, original)
	app.Log.Debugf("serveData - Serving path: %s\n", path)

	mediatype = file.MediaType.Mime

	// The content type is dependent on whether we are
	// serving the original or the converted file.
	if !original && isConvertedImage(file.MediaType.Mime) {
		mediatype = "image/jpeg"
	} else if !original && isExcelSpreadsheet(file.MediaType.Mime) {
		mediatype = "application/pdf"
	}

	return path, mediatype, nil
}

// getOriginalFormValue looks for the original argument on the URL. If it exists
// (has a value specified) then return true. The original flag specifies whether
// the user wants the original rather than the converted data.
func getOriginalFormValue(req *http.Request) bool {
	if req.FormValue("original") == "" {
		return false
	}
	return true
}

// filePath determines which file to serve. If there is a converted image we
// will serve that one up unless the original flag is set to true.
func filePath(file *schema.File, original bool) string {
	switch {
	case isConvertedImage(file.MediaType.Mime) && !original:
		return app.MCDir.FilePathImageConversion(file.FileID())
	case files.IsOfficeDocument(file.MediaType.Mime) && !original:
		return app.MCDir.FilePathFromConversionToPDF(file.FileID())
	default:
		return app.MCDir.FilePath(file.FileID())
	}
}

// isConvertedImage checks a name to see if it is an image type we have converted.
func isConvertedImage(mime string) bool {
	switch mime {
	case "image/tiff":
		return true
	case "image/x-ms-bmp":
		return true
	case "image/bmp":
		return true
	default:
		return false
	}
}

// isExcelSpreadsheet checks the mime type to see if it is an excel spreadsheet
func isExcelSpreadsheet(mime string) bool {
	switch mime {
	case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
		return true
	case "application/vnd.MS-Excel":
		return true
	default:
		return false
	}
}
<|endoftext|>


<commit_before>package server

import (
	"github.com/smancke/guble/guble"
	"github.com/smancke/guble/store"

	"github.com/gorilla/websocket"
	"github.com/rs/xid"

	"fmt"
	"github.com/smancke/guble/server/auth"
	"net/http"
	"strings"
	"time"
)

var webSocketUpgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}

type WSHandler struct {
	Router        PubSubSource
	MessageSink   MessageSink
	prefix        string
	messageStore  store.MessageStore
	accessManager auth.AccessManager
}

func NewWSHandler(router PubSubSource, prefix string) (*WSHandler, error) {
	accessManager, err := router.AccessManager()
	if err != nil {
		return nil, err
	}

	messageStore, err := router.MessageStore()
	if err != nil {
		return nil, err
	}

	return &WSHandler{
		Router:        router,
		prefix:        prefix,
		accessManager: accessManager,
		messageStore:  messageStore,
	}, nil
}

func (handle *WSHandler) GetPrefix() string {
	return handle.prefix
}

func (handle *WSHandler) SetMessageEntry(messageSink MessageSink) {
	handle.MessageSink = messageSink
}

func (handle *WSHandler) SetRouter(router PubSubSource) {
	handle.Router = router
}

func (entry *WSHandler) SetMessageStore(messageStore store.MessageStore) {
	entry.messageStore = messageStore
}

func (entry *WSHandler) SetAccessManager(accessManager auth.AccessManager) {
	entry.accessManager = accessManager
}

func (handle *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c, err := webSocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		guble.Warn("error on upgrading %v", err.Error())
		return
	}
	defer c.Close()

	NewWebSocket(handle, &wsconn{c}, extractUserId(r.RequestURI)).Start()
}

// wsconnImpl is a Wrapper of the websocket.Conn
// implementing the interface WSConn for better testability
type wsconn struct {
	*websocket.Conn
}

func (conn *wsconn) Close() {
	conn.Close()
}

func (conn *wsconn) Send(bytes []byte) (err error) {
	return conn.WriteMessage(websocket.BinaryMessage, bytes)
}

func (conn *wsconn) Receive(bytes *[]byte) (err error) {
	_, *bytes, err = conn.ReadMessage()
	return err
}

// Represents a websocket
type WebSocket struct {
	*WSHandler
	WSConnection
	applicationId string
	userId        string
	sendChannel   chan []byte
	receivers     map[guble.Path]*Receiver
}

func NewWebSocket(handler *WSHandler, wsConn WSConnection, userId string) *WebSocket {
	return &WebSocket{
		WSHandler:     handler,
		WSConnection:  wsConn,
		applicationId: xid.New().String(),
		userId:        userId,
		sendChannel:   make(chan []byte, 10),
		receivers:     make(map[guble.Path]*Receiver),
	}
}

func (ws *WebSocket) Start() error {
	ws.sendConnectionMessage()
	go ws.sendLoop()
	ws.receiveLoop()
	return nil
}

func (ws *WebSocket) sendLoop() {
	for {
		select {
		case raw := <-ws.sendChannel:

			if ws.checkAccess(raw) {
				if guble.DebugEnabled() {
					if len(raw) < 80 {
						guble.Debug("send to client (userId=%v, applicationId=%v, totalSize=%v): %v", ws.userId, ws.applicationId, len(raw), string(raw))
					} else {
						guble.Debug("send to client (userId=%v, applicationId=%v, totalSize=%v): %v...", ws.userId, ws.applicationId, len(raw), string(raw[0:79]))
					}
				}

				if err := ws.Send(raw); err != nil {
					guble.Info("applicationId=%v closed the connection", ws.applicationId)
					ws.cleanAndClose()
					break
				}
			}
		}
	}
}

func (ws *WebSocket) checkAccess(raw []byte) bool {
	guble.Debug("raw message: %v", string(raw))
	if raw[0] == byte('/') {
		path := getPathFromRawMessage(raw)
		guble.Debug("Received msg %v %v", ws.userId, path)
		return len(path) == 0 || ws.accessManager.IsAllowed(auth.READ, ws.userId, path)

	}
	return true
}

func getPathFromRawMessage(raw []byte) guble.Path {
	i := strings.Index(string(raw), ",")
	return guble.Path(raw[:i])
}

func (ws *WebSocket) receiveLoop() {
	var message []byte
	for {
		err := ws.Receive(&message)
		if err != nil {
			guble.Info("applicationId=%v closed the connection", ws.applicationId)
			ws.cleanAndClose()
			break
		}

		//guble.Debug("websocket_connector, raw message received: %v", string(message))
		cmd, err := guble.ParseCmd(message)
		if err != nil {
			ws.sendError(guble.ERROR_BAD_REQUEST, "error parsing command. %v", err.Error())
			continue
		}
		switch cmd.Name {
		case guble.CmdSend:
			ws.handleSendCmd(cmd)
		case guble.CmdReceive:
			ws.handleReceiveCmd(cmd)
		case guble.CmdCancel:
			ws.handleCancelCmd(cmd)
		default:
			ws.sendError(guble.ERROR_BAD_REQUEST, "unknown command %v", cmd.Name)
		}
	}
}

func (ws *WebSocket) sendConnectionMessage() {
	n := &guble.NotificationMessage{
		Name: guble.SUCCESS_CONNECTED,
		Arg:  "You are connected to the server.",
		Json: fmt.Sprintf(`{"ApplicationId": "%s", "UserId": "%s", "Time": "%s"}`, ws.applicationId, ws.userId, time.Now().Format(time.RFC3339)),
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) handleReceiveCmd(cmd *guble.Cmd) {
	rec, err := NewReceiverFromCmd(
		ws.applicationId,
		cmd,
		ws.sendChannel,
		ws.Router,
		ws.messageStore,
		ws.userId,
	)
	if err != nil {
		guble.Info("client error in handleReceiveCmd: %v", err.Error())
		ws.sendError(guble.ERROR_BAD_REQUEST, err.Error())
		return
	}
	ws.receivers[rec.path] = rec
	rec.Start()
}

func (ws *WebSocket) handleCancelCmd(cmd *guble.Cmd) {
	if len(cmd.Arg) == 0 {
		ws.sendError(guble.ERROR_BAD_REQUEST, "- command requires a path argument, but non given")
		return
	}
	path := guble.Path(cmd.Arg)
	rec, exist := ws.receivers[path]
	if exist {
		rec.Stop()
		delete(ws.receivers, path)
	}
}

func (ws *WebSocket) handleSendCmd(cmd *guble.Cmd) {
	guble.Debug("sending %v", string(cmd.Bytes()))
	if len(cmd.Arg) == 0 {
		ws.sendError(guble.ERROR_BAD_REQUEST, "send command requires a path argument, but non given")
		return
	}

	args := strings.SplitN(cmd.Arg, " ", 2)
	msg := &guble.Message{
		Path: guble.Path(args[0]),
		PublisherApplicationId: ws.applicationId,
		PublisherUserId:        ws.userId,
		HeaderJSON:             cmd.HeaderJSON,
		Body:                   cmd.Body,
	}
	if len(args) == 2 {
		msg.PublisherMessageId = args[1]
	}

	ws.MessageSink.HandleMessage(msg)

	ws.sendOK(guble.SUCCESS_SEND, msg.PublisherMessageId)
}

func (ws *WebSocket) cleanAndClose() {
	guble.Info("closing applicationId=%v", ws.applicationId)

	for path, rec := range ws.receivers {
		rec.Stop()
		delete(ws.receivers, path)
	}

	ws.Close()
}

func (ws *WebSocket) sendError(name string, argPattern string, params ...interface{}) {
	n := &guble.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: true,
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) sendOK(name string, argPattern string, params ...interface{}) {
	n := &guble.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: false,
	}
	ws.sendChannel <- n.Bytes()
}
<commit_msg>Remove unnecesarry method<commit_after>package server

import (
	"github.com/smancke/guble/guble"
	"github.com/smancke/guble/store"

	"github.com/gorilla/websocket"
	"github.com/rs/xid"

	"fmt"
	"github.com/smancke/guble/server/auth"
	"net/http"
	"strings"
	"time"
)

var webSocketUpgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}

type WSHandler struct {
	Router        PubSubSource
	MessageSink   MessageSink
	prefix        string
	messageStore  store.MessageStore
	accessManager auth.AccessManager
}

func NewWSHandler(router PubSubSource, prefix string) (*WSHandler, error) {
	accessManager, err := router.AccessManager()
	if err != nil {
		return nil, err
	}

	messageStore, err := router.MessageStore()
	if err != nil {
		return nil, err
	}

	return &WSHandler{
		Router:        router,
		prefix:        prefix,
		accessManager: accessManager,
		messageStore:  messageStore,
	}, nil
}

func (handle *WSHandler) GetPrefix() string {
	return handle.prefix
}

func (handle *WSHandler) SetMessageEntry(messageSink MessageSink) {
	handle.MessageSink = messageSink
}

func (handle *WSHandler) SetRouter(router PubSubSource) {
	handle.Router = router
}

func (entry *WSHandler) SetAccessManager(accessManager auth.AccessManager) {
	entry.accessManager = accessManager
}

func (handle *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c, err := webSocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		guble.Warn("error on upgrading %v", err.Error())
		return
	}
	defer c.Close()

	NewWebSocket(handle, &wsconn{c}, extractUserId(r.RequestURI)).Start()
}

// wsconnImpl is a Wrapper of the websocket.Conn
// implementing the interface WSConn for better testability
type wsconn struct {
	*websocket.Conn
}

func (conn *wsconn) Close() {
	conn.Close()
}

func (conn *wsconn) Send(bytes []byte) (err error) {
	return conn.WriteMessage(websocket.BinaryMessage, bytes)
}

func (conn *wsconn) Receive(bytes *[]byte) (err error) {
	_, *bytes, err = conn.ReadMessage()
	return err
}

// Represents a websocket
type WebSocket struct {
	*WSHandler
	WSConnection
	applicationId string
	userId        string
	sendChannel   chan []byte
	receivers     map[guble.Path]*Receiver
}

func NewWebSocket(handler *WSHandler, wsConn WSConnection, userId string) *WebSocket {
	return &WebSocket{
		WSHandler:     handler,
		WSConnection:  wsConn,
		applicationId: xid.New().String(),
		userId:        userId,
		sendChannel:   make(chan []byte, 10),
		receivers:     make(map[guble.Path]*Receiver),
	}
}

func (ws *WebSocket) Start() error {
	ws.sendConnectionMessage()
	go ws.sendLoop()
	ws.receiveLoop()
	return nil
}

func (ws *WebSocket) sendLoop() {
	for {
		select {
		case raw := <-ws.sendChannel:

			if ws.checkAccess(raw) {
				if guble.DebugEnabled() {
					if len(raw) < 80 {
						guble.Debug("send to client (userId=%v, applicationId=%v, totalSize=%v): %v", ws.userId, ws.applicationId, len(raw), string(raw))
					} else {
						guble.Debug("send to client (userId=%v, applicationId=%v, totalSize=%v): %v...", ws.userId, ws.applicationId, len(raw), string(raw[0:79]))
					}
				}

				if err := ws.Send(raw); err != nil {
					guble.Info("applicationId=%v closed the connection", ws.applicationId)
					ws.cleanAndClose()
					break
				}
			}
		}
	}
}

func (ws *WebSocket) checkAccess(raw []byte) bool {
	guble.Debug("raw message: %v", string(raw))
	if raw[0] == byte('/') {
		path := getPathFromRawMessage(raw)
		guble.Debug("Received msg %v %v", ws.userId, path)
		return len(path) == 0 || ws.accessManager.IsAllowed(auth.READ, ws.userId, path)

	}
	return true
}

func getPathFromRawMessage(raw []byte) guble.Path {
	i := strings.Index(string(raw), ",")
	return guble.Path(raw[:i])
}

func (ws *WebSocket) receiveLoop() {
	var message []byte
	for {
		err := ws.Receive(&message)
		if err != nil {
			guble.Info("applicationId=%v closed the connection", ws.applicationId)
			ws.cleanAndClose()
			break
		}

		//guble.Debug("websocket_connector, raw message received: %v", string(message))
		cmd, err := guble.ParseCmd(message)
		if err != nil {
			ws.sendError(guble.ERROR_BAD_REQUEST, "error parsing command. %v", err.Error())
			continue
		}
		switch cmd.Name {
		case guble.CmdSend:
			ws.handleSendCmd(cmd)
		case guble.CmdReceive:
			ws.handleReceiveCmd(cmd)
		case guble.CmdCancel:
			ws.handleCancelCmd(cmd)
		default:
			ws.sendError(guble.ERROR_BAD_REQUEST, "unknown command %v", cmd.Name)
		}
	}
}

func (ws *WebSocket) sendConnectionMessage() {
	n := &guble.NotificationMessage{
		Name: guble.SUCCESS_CONNECTED,
		Arg:  "You are connected to the server.",
		Json: fmt.Sprintf(`{"ApplicationId": "%s", "UserId": "%s", "Time": "%s"}`, ws.applicationId, ws.userId, time.Now().Format(time.RFC3339)),
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) handleReceiveCmd(cmd *guble.Cmd) {
	rec, err := NewReceiverFromCmd(
		ws.applicationId,
		cmd,
		ws.sendChannel,
		ws.Router,
		ws.messageStore,
		ws.userId,
	)
	if err != nil {
		guble.Info("client error in handleReceiveCmd: %v", err.Error())
		ws.sendError(guble.ERROR_BAD_REQUEST, err.Error())
		return
	}
	ws.receivers[rec.path] = rec
	rec.Start()
}

func (ws *WebSocket) handleCancelCmd(cmd *guble.Cmd) {
	if len(cmd.Arg) == 0 {
		ws.sendError(guble.ERROR_BAD_REQUEST, "- command requires a path argument, but non given")
		return
	}
	path := guble.Path(cmd.Arg)
	rec, exist := ws.receivers[path]
	if exist {
		rec.Stop()
		delete(ws.receivers, path)
	}
}

func (ws *WebSocket) handleSendCmd(cmd *guble.Cmd) {
	guble.Debug("sending %v", string(cmd.Bytes()))
	if len(cmd.Arg) == 0 {
		ws.sendError(guble.ERROR_BAD_REQUEST, "send command requires a path argument, but non given")
		return
	}

	args := strings.SplitN(cmd.Arg, " ", 2)
	msg := &guble.Message{
		Path: guble.Path(args[0]),
		PublisherApplicationId: ws.applicationId,
		PublisherUserId:        ws.userId,
		HeaderJSON:             cmd.HeaderJSON,
		Body:                   cmd.Body,
	}
	if len(args) == 2 {
		msg.PublisherMessageId = args[1]
	}

	ws.MessageSink.HandleMessage(msg)

	ws.sendOK(guble.SUCCESS_SEND, msg.PublisherMessageId)
}

func (ws *WebSocket) cleanAndClose() {
	guble.Info("closing applicationId=%v", ws.applicationId)

	for path, rec := range ws.receivers {
		rec.Stop()
		delete(ws.receivers, path)
	}

	ws.Close()
}

func (ws *WebSocket) sendError(name string, argPattern string, params ...interface{}) {
	n := &guble.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: true,
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) sendOK(name string, argPattern string, params ...interface{}) {
	n := &guble.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: false,
	}
	ws.sendChannel <- n.Bytes()
}
<|endoftext|>


<commit_before>package debugger

import (
	"debug/gosym"
	"fmt"
	"go/constant"
	"path/filepath"
	"reflect"
	"runtime"
	"strconv"
	"strings"

	"github.com/derekparker/delve/pkg/proc"
	"github.com/derekparker/delve/service/api"
)

const maxFindLocationCandidates = 5

type LocationSpec interface {
	Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error)
}

type NormalLocationSpec struct {
	Base       string
	FuncBase   *FuncLocationSpec
	LineOffset int
}

type RegexLocationSpec struct {
	FuncRegex string
}

type AddrLocationSpec struct {
	AddrExpr string
}

type OffsetLocationSpec struct {
	Offset int
}

type LineLocationSpec struct {
	Line int
}

type FuncLocationSpec struct {
	PackageName           string
	AbsolutePackage       bool
	ReceiverName          string
	PackageOrReceiverName string
	BaseName              string
}

func parseLocationSpec(locStr string) (LocationSpec, error) {
	rest := locStr

	malformed := func(reason string) error {
		return fmt.Errorf("Malformed breakpoint location \"%s\" at %d: %s", locStr, len(locStr)-len(rest), reason)
	}

	if len(rest) <= 0 {
		return nil, malformed("empty string")
	}

	switch rest[0] {
	case '+', '-':
		offset, err := strconv.Atoi(rest)
		if err != nil {
			return nil, malformed(err.Error())
		}
		return &OffsetLocationSpec{offset}, nil

	case '/':
		if rest[len(rest)-1] == '/' {
			rx, rest := readRegex(rest[1:])
			if len(rest) < 0 {
				return nil, malformed("non-terminated regular expression")
			}
			if len(rest) > 1 {
				return nil, malformed("no line offset can be specified for regular expression locations")
			}
			return &RegexLocationSpec{rx}, nil
		} else {
			return parseLocationSpecDefault(locStr, rest)
		}

	case '*':
		return &AddrLocationSpec{rest[1:]}, nil

	default:
		return parseLocationSpecDefault(locStr, rest)
	}
}

func parseLocationSpecDefault(locStr, rest string) (LocationSpec, error) {
	malformed := func(reason string) error {
		return fmt.Errorf("Malformed breakpoint location \"%s\" at %d: %s", locStr, len(locStr)-len(rest), reason)
	}

	v := strings.Split(rest, ":")
	if len(v) > 2 {
		// On Windows, path may contain ":", so split only on last ":"
		v = []string{strings.Join(v[0:len(v)-1], ":"), v[len(v)-1]}
	}

	if len(v) == 1 {
		n, err := strconv.ParseInt(v[0], 0, 64)
		if err == nil {
			return &LineLocationSpec{int(n)}, nil
		}
	}

	spec := &NormalLocationSpec{}

	spec.Base = v[0]
	spec.FuncBase = parseFuncLocationSpec(spec.Base)

	if len(v) < 2 {
		spec.LineOffset = -1
		return spec, nil
	}

	rest = v[1]

	var err error
	spec.LineOffset, err = strconv.Atoi(rest)
	if err != nil || spec.LineOffset < 0 {
		return nil, malformed("line offset negative or not a number")
	}

	return spec, nil
}

func readRegex(in string) (rx string, rest string) {
	out := make([]rune, 0, len(in))
	escaped := false
	for i, ch := range in {
		if escaped {
			if ch == '/' {
				out = append(out, '/')
			} else {
				out = append(out, '\\')
				out = append(out, ch)
			}
			escaped = false
		} else {
			switch ch {
			case '\\':
				escaped = true
			case '/':
				return string(out), in[i:]
			default:
				out = append(out, ch)
			}
		}
	}
	return string(out), ""
}

func parseFuncLocationSpec(in string) *FuncLocationSpec {
	var v []string
	pathend := strings.LastIndex(in, "/")
	if pathend < 0 {
		v = strings.Split(in, ".")
	} else {
		v = strings.Split(in[pathend:], ".")
		if len(v) > 0 {
			v[0] = in[:pathend] + v[0]
		}
	}

	var spec FuncLocationSpec
	switch len(v) {
	case 1:
		spec.BaseName = v[0]

	case 2:
		spec.BaseName = v[1]
		r := stripReceiverDecoration(v[0])
		if r != v[0] {
			spec.ReceiverName = r
		} else if strings.Contains(r, "/") {
			spec.PackageName = r
		} else {
			spec.PackageOrReceiverName = r
		}

	case 3:
		spec.BaseName = v[2]
		spec.ReceiverName = stripReceiverDecoration(v[1])
		spec.PackageName = v[0]

	default:
		return nil
	}

	if strings.HasPrefix(spec.PackageName, "/") {
		spec.PackageName = spec.PackageName[1:]
		spec.AbsolutePackage = true
	}

	if strings.Contains(spec.BaseName, "/") || strings.Contains(spec.ReceiverName, "/") {
		return nil
	}

	return &spec
}

func stripReceiverDecoration(in string) string {
	if len(in) < 3 {
		return in
	}
	if (in[0] != '(') || (in[1] != '*') || (in[len(in)-1] != ')') {
		return in
	}

	return in[2 : len(in)-1]
}

func (spec *FuncLocationSpec) Match(sym *gosym.Sym) bool {
	if spec.BaseName != sym.BaseName() {
		return false
	}

	recv := stripReceiverDecoration(sym.ReceiverName())
	if spec.ReceiverName != "" && spec.ReceiverName != recv {
		return false
	}
	if spec.PackageName != "" {
		if spec.AbsolutePackage {
			if spec.PackageName != sym.PackageName() {
				return false
			}
		} else {
			if !partialPathMatch(spec.PackageName, sym.PackageName()) {
				return false
			}
		}
	}
	if spec.PackageOrReceiverName != "" && !partialPathMatch(spec.PackageOrReceiverName, sym.PackageName()) && spec.PackageOrReceiverName != recv {
		return false
	}
	return true
}

func (loc *RegexLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {
	funcs := d.target.BinInfo().Funcs()
	matches, err := regexFilterFuncs(loc.FuncRegex, funcs)
	if err != nil {
		return nil, err
	}
	r := make([]api.Location, 0, len(matches))
	for i := range matches {
		addr, err := proc.FindFunctionLocation(d.target, matches[i], true, 0)
		if err == nil {
			r = append(r, api.Location{PC: addr})
		}
	}
	return r, nil
}

func (loc *AddrLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {
	if scope == nil {
		addr, err := strconv.ParseInt(loc.AddrExpr, 0, 64)
		if err != nil {
			return nil, fmt.Errorf("could not determine current location (scope is nil)")
		}
		return []api.Location{{PC: uint64(addr)}}, nil
	} else {
		v, err := scope.EvalExpression(loc.AddrExpr, proc.LoadConfig{true, 0, 0, 0, 0})
		if err != nil {
			return nil, err
		}
		if v.Unreadable != nil {
			return nil, v.Unreadable
		}
		switch v.Kind {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
			addr, _ := constant.Uint64Val(v.Value)
			return []api.Location{{PC: addr}}, nil
		case reflect.Func:
			_, _, fn := d.target.BinInfo().PCToLine(uint64(v.Base))
			pc, err := proc.FirstPCAfterPrologue(d.target, fn, false)
			if err != nil {
				return nil, err
			}
			return []api.Location{{PC: uint64(pc)}}, nil
		default:
			return nil, fmt.Errorf("wrong expression kind: %v", v.Kind)
		}
	}
}

func (loc *NormalLocationSpec) FileMatch(path string) bool {
	return partialPathMatch(loc.Base, path)
}

func partialPathMatch(expr, path string) bool {
	if runtime.GOOS == "windows" {
		// Accept `expr` which is case-insensitive and slash-insensitive match to `path`
		expr = strings.ToLower(filepath.ToSlash(expr))
		path = strings.ToLower(filepath.ToSlash(path))
	}
	if len(expr) < len(path)-1 {
		return strings.HasSuffix(path, expr) && (path[len(path)-len(expr)-1] == '/')
	} else {
		return expr == path
	}
}

type AmbiguousLocationError struct {
	Location           string
	CandidatesString   []string
	CandidatesLocation []api.Location
}

func (ale AmbiguousLocationError) Error() string {
	var candidates []string
	if ale.CandidatesLocation != nil {
		for i := range ale.CandidatesLocation {
			candidates = append(candidates, ale.CandidatesLocation[i].Function.Name)
		}

	} else {
		candidates = ale.CandidatesString
	}
	return fmt.Sprintf("Location \"%s\" ambiguous: %s…", ale.Location, strings.Join(candidates, ", "))
}

func (loc *NormalLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {
	funcs := d.target.BinInfo().Funcs()
	files := d.target.BinInfo().Sources()

	candidates := []string{}
	for file := range files {
		if loc.FileMatch(file) {
			candidates = append(candidates, file)
			if len(candidates) >= maxFindLocationCandidates {
				break
			}
		}
	}

	if loc.FuncBase != nil {
		for _, f := range funcs {
			if f.Sym == nil {
				continue
			}
			if loc.FuncBase.Match(f.Sym) {
				if loc.Base == f.Name {
					// if an exact match for the function name is found use it
					candidates = []string{f.Name}
					break
				}
				if len(candidates) < maxFindLocationCandidates {
					candidates = append(candidates, f.Name)
				}
			}
		}
	}

	switch len(candidates) {
	case 1:
		var addr uint64
		var err error
		if filepath.IsAbs(candidates[0]) {
			if loc.LineOffset < 0 {
				return nil, fmt.Errorf("Malformed breakpoint location, no line offset specified")
			}
			addr, err = proc.FindFileLocation(d.target, candidates[0], loc.LineOffset)
		} else {
			if loc.LineOffset < 0 {
				addr, err = proc.FindFunctionLocation(d.target, candidates[0], true, 0)
			} else {
				addr, err = proc.FindFunctionLocation(d.target, candidates[0], false, loc.LineOffset)
			}
		}
		if err != nil {
			return nil, err
		}
		return []api.Location{{PC: addr}}, nil

	case 0:
		return nil, fmt.Errorf("Location \"%s\" not found", locStr)
	default:
		return nil, AmbiguousLocationError{Location: locStr, CandidatesString: candidates}
	}
}

func (loc *OffsetLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {
	if scope == nil {
		return nil, fmt.Errorf("could not determine current location (scope is nil)")
	}
	file, line, fn := d.target.BinInfo().PCToLine(scope.PC)
	if fn == nil {
		return nil, fmt.Errorf("could not determine current location")
	}
	addr, err := proc.FindFileLocation(d.target, file, line+loc.Offset)
	return []api.Location{{PC: addr}}, err
}

func (loc *LineLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {
	if scope == nil {
		return nil, fmt.Errorf("could not determine current location (scope is nil)")
	}
	file, _, fn := d.target.BinInfo().PCToLine(scope.PC)
	if fn == nil {
		return nil, fmt.Errorf("could not determine current location")
	}
	addr, err := proc.FindFileLocation(d.target, file, loc.Line)
	return []api.Location{{PC: addr}}, err
}
<commit_msg>service/debugger: improve NomalLocationSpec.Find's heuristics (#923)<commit_after>package debugger

import (
	"debug/gosym"
	"fmt"
	"go/constant"
	"path/filepath"
	"reflect"
	"runtime"
	"strconv"
	"strings"

	"github.com/derekparker/delve/pkg/proc"
	"github.com/derekparker/delve/service/api"
)

const maxFindLocationCandidates = 5

type LocationSpec interface {
	Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error)
}

type NormalLocationSpec struct {
	Base       string
	FuncBase   *FuncLocationSpec
	LineOffset int
}

type RegexLocationSpec struct {
	FuncRegex string
}

type AddrLocationSpec struct {
	AddrExpr string
}

type OffsetLocationSpec struct {
	Offset int
}

type LineLocationSpec struct {
	Line int
}

type FuncLocationSpec struct {
	PackageName           string
	AbsolutePackage       bool
	ReceiverName          string
	PackageOrReceiverName string
	BaseName              string
}

func parseLocationSpec(locStr string) (LocationSpec, error) {
	rest := locStr

	malformed := func(reason string) error {
		return fmt.Errorf("Malformed breakpoint location \"%s\" at %d: %s", locStr, len(locStr)-len(rest), reason)
	}

	if len(rest) <= 0 {
		return nil, malformed("empty string")
	}

	switch rest[0] {
	case '+', '-':
		offset, err := strconv.Atoi(rest)
		if err != nil {
			return nil, malformed(err.Error())
		}
		return &OffsetLocationSpec{offset}, nil

	case '/':
		if rest[len(rest)-1] == '/' {
			rx, rest := readRegex(rest[1:])
			if len(rest) < 0 {
				return nil, malformed("non-terminated regular expression")
			}
			if len(rest) > 1 {
				return nil, malformed("no line offset can be specified for regular expression locations")
			}
			return &RegexLocationSpec{rx}, nil
		} else {
			return parseLocationSpecDefault(locStr, rest)
		}

	case '*':
		return &AddrLocationSpec{rest[1:]}, nil

	default:
		return parseLocationSpecDefault(locStr, rest)
	}
}

func parseLocationSpecDefault(locStr, rest string) (LocationSpec, error) {
	malformed := func(reason string) error {
		return fmt.Errorf("Malformed breakpoint location \"%s\" at %d: %s", locStr, len(locStr)-len(rest), reason)
	}

	v := strings.Split(rest, ":")
	if len(v) > 2 {
		// On Windows, path may contain ":", so split only on last ":"
		v = []string{strings.Join(v[0:len(v)-1], ":"), v[len(v)-1]}
	}

	if len(v) == 1 {
		n, err := strconv.ParseInt(v[0], 0, 64)
		if err == nil {
			return &LineLocationSpec{int(n)}, nil
		}
	}

	spec := &NormalLocationSpec{}

	spec.Base = v[0]
	spec.FuncBase = parseFuncLocationSpec(spec.Base)

	if len(v) < 2 {
		spec.LineOffset = -1
		return spec, nil
	}

	rest = v[1]

	var err error
	spec.LineOffset, err = strconv.Atoi(rest)
	if err != nil || spec.LineOffset < 0 {
		return nil, malformed("line offset negative or not a number")
	}

	return spec, nil
}

func readRegex(in string) (rx string, rest string) {
	out := make([]rune, 0, len(in))
	escaped := false
	for i, ch := range in {
		if escaped {
			if ch == '/' {
				out = append(out, '/')
			} else {
				out = append(out, '\\')
				out = append(out, ch)
			}
			escaped = false
		} else {
			switch ch {
			case '\\':
				escaped = true
			case '/':
				return string(out), in[i:]
			default:
				out = append(out, ch)
			}
		}
	}
	return string(out), ""
}

func parseFuncLocationSpec(in string) *FuncLocationSpec {
	var v []string
	pathend := strings.LastIndex(in, "/")
	if pathend < 0 {
		v = strings.Split(in, ".")
	} else {
		v = strings.Split(in[pathend:], ".")
		if len(v) > 0 {
			v[0] = in[:pathend] + v[0]
		}
	}

	var spec FuncLocationSpec
	switch len(v) {
	case 1:
		spec.BaseName = v[0]

	case 2:
		spec.BaseName = v[1]
		r := stripReceiverDecoration(v[0])
		if r != v[0] {
			spec.ReceiverName = r
		} else if strings.Contains(r, "/") {
			spec.PackageName = r
		} else {
			spec.PackageOrReceiverName = r
		}

	case 3:
		spec.BaseName = v[2]
		spec.ReceiverName = stripReceiverDecoration(v[1])
		spec.PackageName = v[0]

	default:
		return nil
	}

	if strings.HasPrefix(spec.PackageName, "/") {
		spec.PackageName = spec.PackageName[1:]
		spec.AbsolutePackage = true
	}

	if strings.Contains(spec.BaseName, "/") || strings.Contains(spec.ReceiverName, "/") {
		return nil
	}

	return &spec
}

func stripReceiverDecoration(in string) string {
	if len(in) < 3 {
		return in
	}
	if (in[0] != '(') || (in[1] != '*') || (in[len(in)-1] != ')') {
		return in
	}

	return in[2 : len(in)-1]
}

func (spec *FuncLocationSpec) Match(sym *gosym.Sym) bool {
	if spec.BaseName != sym.BaseName() {
		return false
	}

	recv := stripReceiverDecoration(sym.ReceiverName())
	if spec.ReceiverName != "" && spec.ReceiverName != recv {
		return false
	}
	if spec.PackageName != "" {
		if spec.AbsolutePackage {
			if spec.PackageName != sym.PackageName() {
				return false
			}
		} else {
			if !partialPathMatch(spec.PackageName, sym.PackageName()) {
				return false
			}
		}
	}
	if spec.PackageOrReceiverName != "" && !partialPathMatch(spec.PackageOrReceiverName, sym.PackageName()) && spec.PackageOrReceiverName != recv {
		return false
	}
	return true
}

func (loc *RegexLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {
	funcs := d.target.BinInfo().Funcs()
	matches, err := regexFilterFuncs(loc.FuncRegex, funcs)
	if err != nil {
		return nil, err
	}
	r := make([]api.Location, 0, len(matches))
	for i := range matches {
		addr, err := proc.FindFunctionLocation(d.target, matches[i], true, 0)
		if err == nil {
			r = append(r, api.Location{PC: addr})
		}
	}
	return r, nil
}

func (loc *AddrLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {
	if scope == nil {
		addr, err := strconv.ParseInt(loc.AddrExpr, 0, 64)
		if err != nil {
			return nil, fmt.Errorf("could not determine current location (scope is nil)")
		}
		return []api.Location{{PC: uint64(addr)}}, nil
	} else {
		v, err := scope.EvalExpression(loc.AddrExpr, proc.LoadConfig{true, 0, 0, 0, 0})
		if err != nil {
			return nil, err
		}
		if v.Unreadable != nil {
			return nil, v.Unreadable
		}
		switch v.Kind {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
			addr, _ := constant.Uint64Val(v.Value)
			return []api.Location{{PC: addr}}, nil
		case reflect.Func:
			_, _, fn := d.target.BinInfo().PCToLine(uint64(v.Base))
			pc, err := proc.FirstPCAfterPrologue(d.target, fn, false)
			if err != nil {
				return nil, err
			}
			return []api.Location{{PC: uint64(pc)}}, nil
		default:
			return nil, fmt.Errorf("wrong expression kind: %v", v.Kind)
		}
	}
}

func (loc *NormalLocationSpec) FileMatch(path string) bool {
	return partialPathMatch(loc.Base, path)
}

func partialPathMatch(expr, path string) bool {
	if runtime.GOOS == "windows" {
		// Accept `expr` which is case-insensitive and slash-insensitive match to `path`
		expr = strings.ToLower(filepath.ToSlash(expr))
		path = strings.ToLower(filepath.ToSlash(path))
	}
	if len(expr) < len(path)-1 {
		return strings.HasSuffix(path, expr) && (path[len(path)-len(expr)-1] == '/')
	} else {
		return expr == path
	}
}

type AmbiguousLocationError struct {
	Location           string
	CandidatesString   []string
	CandidatesLocation []api.Location
}

func (ale AmbiguousLocationError) Error() string {
	var candidates []string
	if ale.CandidatesLocation != nil {
		for i := range ale.CandidatesLocation {
			candidates = append(candidates, ale.CandidatesLocation[i].Function.Name)
		}

	} else {
		candidates = ale.CandidatesString
	}
	return fmt.Sprintf("Location \"%s\" ambiguous: %s…", ale.Location, strings.Join(candidates, ", "))
}

func (loc *NormalLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {
	limit := maxFindLocationCandidates
	var candidateFiles []string
	for file := range d.target.BinInfo().Sources() {
		if loc.FileMatch(file) {
			candidateFiles = append(candidateFiles, file)
			if len(candidateFiles) >= limit {
				break
			}
		}
	}

	limit -= len(candidateFiles)

	var candidateFuncs []string
	if loc.FuncBase != nil {
		for _, f := range d.target.BinInfo().Funcs() {
			if f.Sym == nil {
				continue
			}
			if !loc.FuncBase.Match(f.Sym) {
				continue
			}
			if loc.Base == f.Name {
				// if an exact match for the function name is found use it
				candidateFuncs = []string{f.Name}
				break
			}
			candidateFuncs = append(candidateFuncs, f.Name)
			if len(candidateFuncs) >= limit {
				break
			}
		}
	}

	if matching := len(candidateFiles) + len(candidateFuncs); matching == 0 {
		return nil, fmt.Errorf("Location %q not found", locStr)
	} else if matching > 1 {
		return nil, AmbiguousLocationError{Location: locStr, CandidatesString: append(candidateFiles, candidateFuncs...)}
	}

	// len(candidateFiles) + len(candidateFuncs) == 1
	var addr uint64
	var err error
	if len(candidateFiles) == 1 {
		if loc.LineOffset < 0 {
			return nil, fmt.Errorf("Malformed breakpoint location, no line offset specified")
		}
		addr, err = proc.FindFileLocation(d.target, candidateFiles[0], loc.LineOffset)
	} else { // len(candidateFUncs) == 1
		if loc.LineOffset < 0 {
			addr, err = proc.FindFunctionLocation(d.target, candidateFuncs[0], true, 0)
		} else {
			addr, err = proc.FindFunctionLocation(d.target, candidateFuncs[0], false, loc.LineOffset)
		}
	}

	if err != nil {
		return nil, err
	}
	return []api.Location{{PC: addr}}, nil
}

func (loc *OffsetLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {
	if scope == nil {
		return nil, fmt.Errorf("could not determine current location (scope is nil)")
	}
	file, line, fn := d.target.BinInfo().PCToLine(scope.PC)
	if fn == nil {
		return nil, fmt.Errorf("could not determine current location")
	}
	addr, err := proc.FindFileLocation(d.target, file, line+loc.Offset)
	return []api.Location{{PC: addr}}, err
}

func (loc *LineLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {
	if scope == nil {
		return nil, fmt.Errorf("could not determine current location (scope is nil)")
	}
	file, _, fn := d.target.BinInfo().PCToLine(scope.PC)
	if fn == nil {
		return nil, fmt.Errorf("could not determine current location")
	}
	addr, err := proc.FindFileLocation(d.target, file, loc.Line)
	return []api.Location{{PC: addr}}, err
}
<|endoftext|>


<commit_before>// proxyd is a daemon that listens for connections from veyron services
// (typically behind NATs) and proxies these services to the outside world.
package main

import (
	"flag"
	"net/http"
	_ "net/http/pprof"
	"time"

	"veyron/runtimes/google/ipc/stream/proxy"
	"veyron/runtimes/google/lib/publisher"
	"veyron2/naming"
	"veyron2/rt"
	"veyron2/vlog"
)

func main() {
	var (
		// TODO(rthellend): Remove the address and protocol flags when the config manager is working.
		address     = flag.String("address", ":0", "Network address the proxy listens on")
		pubAddress  = flag.String("published_address", "", "Network address the proxy publishes. If empty, the value of --address will be used")
		protocol    = flag.String("protocol", "tcp", "Network type the proxy listens on")
		httpAddr    = flag.String("http", ":14142", "Network address on which the HTTP debug server runs")
		healthzAddr = flag.String("healthz_address", "", "Network address on which the HTTP healthz server runs. It is intended to be used with a load balancer. The load balancer must be able to reach this address in order to verify that the proxy server is running")
		name        = flag.String("name", "", "Name to mount the proxy as")
	)

	r := rt.Init()
	defer r.Cleanup()

	rid, err := naming.NewRoutingID()
	if err != nil {
		vlog.Fatal(err)
	}

	proxy, err := proxy.New(rid, nil, *protocol, *address, *pubAddress)
	if err != nil {
		vlog.Fatal(err)
	}
	defer proxy.Shutdown()

	if len(*name) > 0 {
		publisher := publisher.New(r.NewContext(), r.Namespace(), time.Minute)
		defer publisher.WaitForStop()
		defer publisher.Stop()
		publisher.AddServer(naming.JoinAddressName(proxy.Endpoint().String(), ""))
		publisher.AddName(*name)
	}

	if len(*healthzAddr) != 0 {
		go startHealthzServer(*healthzAddr)
	}

	http.Handle("/", proxy)
	if err = http.ListenAndServe(*httpAddr, nil); err != nil {
		vlog.Fatal(err)
	}
}

// healthzHandler implements net/http.Handler
type healthzHandler struct{}

func (healthzHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("ok"))
}

// startHealthzServer starts a HTTP server that simply returns "ok" to every
// request. This is needed to let the load balancer know that the proxy server
// is running.
func startHealthzServer(addr string) {
	s := http.Server{
		Addr:         addr,
		Handler:      healthzHandler{},
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
	}
	if err := s.ListenAndServe(); err != nil {
		vlog.Fatal(err)
	}
}
<commit_msg>veyron/services/proxy/proxyd: Add // to the published address.<commit_after>// proxyd is a daemon that listens for connections from veyron services
// (typically behind NATs) and proxies these services to the outside world.
package main

import (
	"flag"
	"net/http"
	_ "net/http/pprof"
	"time"

	"veyron/runtimes/google/ipc/stream/proxy"
	"veyron/runtimes/google/lib/publisher"
	"veyron2/naming"
	"veyron2/rt"
	"veyron2/vlog"
)

func main() {
	var (
		// TODO(rthellend): Remove the address and protocol flags when the config manager is working.
		address     = flag.String("address", ":0", "Network address the proxy listens on")
		pubAddress  = flag.String("published_address", "", "Network address the proxy publishes. If empty, the value of --address will be used")
		protocol    = flag.String("protocol", "tcp", "Network type the proxy listens on")
		httpAddr    = flag.String("http", ":14142", "Network address on which the HTTP debug server runs")
		healthzAddr = flag.String("healthz_address", "", "Network address on which the HTTP healthz server runs. It is intended to be used with a load balancer. The load balancer must be able to reach this address in order to verify that the proxy server is running")
		name        = flag.String("name", "", "Name to mount the proxy as")
	)

	r := rt.Init()
	defer r.Cleanup()

	rid, err := naming.NewRoutingID()
	if err != nil {
		vlog.Fatal(err)
	}

	proxy, err := proxy.New(rid, nil, *protocol, *address, *pubAddress)
	if err != nil {
		vlog.Fatal(err)
	}
	defer proxy.Shutdown()

	if len(*name) > 0 {
		publisher := publisher.New(r.NewContext(), r.Namespace(), time.Minute)
		defer publisher.WaitForStop()
		defer publisher.Stop()
		publisher.AddServer(naming.JoinAddressName(proxy.Endpoint().String(), "//"))
		publisher.AddName(*name)
	}

	if len(*healthzAddr) != 0 {
		go startHealthzServer(*healthzAddr)
	}

	http.Handle("/", proxy)
	if err = http.ListenAndServe(*httpAddr, nil); err != nil {
		vlog.Fatal(err)
	}
}

// healthzHandler implements net/http.Handler
type healthzHandler struct{}

func (healthzHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("ok"))
}

// startHealthzServer starts a HTTP server that simply returns "ok" to every
// request. This is needed to let the load balancer know that the proxy server
// is running.
func startHealthzServer(addr string) {
	s := http.Server{
		Addr:         addr,
		Handler:      healthzHandler{},
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
	}
	if err := s.ListenAndServe(); err != nil {
		vlog.Fatal(err)
	}
}
<|endoftext|>