<commit_before>package proxyproto

// AddressFamilyAndProtocol represents address family and transport protocol.
type AddressFamilyAndProtocol byte

const (
	UNSPEC       AddressFamilyAndProtocol = '\x00'
	TCPv4        AddressFamilyAndProtocol = '\x11'
	UDPv4        AddressFamilyAndProtocol = '\x12'
	TCPv6        AddressFamilyAndProtocol = '\x21'
	UDPv6        AddressFamilyAndProtocol = '\x22'
	UnixStream   AddressFamilyAndProtocol = '\x31'
	UnixDatagram AddressFamilyAndProtocol = '\x32'
)

// IsIPv4 returns true if the address family is IPv4 (AF_INET4), false otherwise.
func (ap AddressFamilyAndProtocol) IsIPv4() bool {
	return 0x10 == ap&0xF0
}

// IsIPv6 returns true if the address family is IPv6 (AF_INET6), false otherwise.
func (ap AddressFamilyAndProtocol) IsIPv6() bool {
	return 0x20 == ap&0xF0
}

// IsUnix returns true if the address family is UNIX (AF_UNIX), false otherwise.
func (ap AddressFamilyAndProtocol) IsUnix() bool {
	return 0x30 == ap&0xF0
}

// IsStream returns true if the transport protocol is TCP or STREAM (SOCK_STREAM), false otherwise.
func (ap AddressFamilyAndProtocol) IsStream() bool {
	return 0x01 == ap&0x0F
}

// IsDatagram returns true if the transport protocol is UDP or DGRAM (SOCK_DGRAM), false otherwise.
func (ap AddressFamilyAndProtocol) IsDatagram() bool {
	return 0x02 == ap&0x0F
}

// IsUnspec returns true if the transport protocol or address family is unspecified, false otherwise.
func (ap AddressFamilyAndProtocol) IsUnspec() bool {
	return (0x00 == ap&0xF0) || (0x00 == ap&0x0F)
}

func (ap AddressFamilyAndProtocol) toByte() byte {
	if ap.IsIPv4() && ap.IsStream() {
		return byte(TCPv4)
	} else if ap.IsIPv4() && ap.IsDatagram() {
		return byte(UDPv4)
	} else if ap.IsIPv6() && ap.IsStream() {
		return byte(TCPv6)
	} else if ap.IsIPv6() && ap.IsDatagram() {
		return byte(UDPv6)
	} else if ap.IsUnix() && ap.IsStream() {
		return byte(UnixStream)
	} else if ap.IsUnix() && ap.IsDatagram() {
		return byte(UnixDatagram)
	}

	return byte(UNSPEC)
}
<commit_msg>fix staticcheck warning: don't use Yoda conditions (ST1017)<commit_after>package proxyproto

// AddressFamilyAndProtocol represents address family and transport protocol.
type AddressFamilyAndProtocol byte

const (
	UNSPEC       AddressFamilyAndProtocol = '\x00'
	TCPv4        AddressFamilyAndProtocol = '\x11'
	UDPv4        AddressFamilyAndProtocol = '\x12'
	TCPv6        AddressFamilyAndProtocol = '\x21'
	UDPv6        AddressFamilyAndProtocol = '\x22'
	UnixStream   AddressFamilyAndProtocol = '\x31'
	UnixDatagram AddressFamilyAndProtocol = '\x32'
)

// IsIPv4 returns true if the address family is IPv4 (AF_INET4), false otherwise.
func (ap AddressFamilyAndProtocol) IsIPv4() bool {
	return ap&0xF0 == 0x10
}

// IsIPv6 returns true if the address family is IPv6 (AF_INET6), false otherwise.
func (ap AddressFamilyAndProtocol) IsIPv6() bool {
	return ap&0xF0 == 0x20
}

// IsUnix returns true if the address family is UNIX (AF_UNIX), false otherwise.
func (ap AddressFamilyAndProtocol) IsUnix() bool {
	return ap&0xF0 == 0x30
}

// IsStream returns true if the transport protocol is TCP or STREAM (SOCK_STREAM), false otherwise.
func (ap AddressFamilyAndProtocol) IsStream() bool {
	return ap&0x0F == 0x01
}

// IsDatagram returns true if the transport protocol is UDP or DGRAM (SOCK_DGRAM), false otherwise.
func (ap AddressFamilyAndProtocol) IsDatagram() bool {
	return ap&0x0F == 0x02
}

// IsUnspec returns true if the transport protocol or address family is unspecified, false otherwise.
func (ap AddressFamilyAndProtocol) IsUnspec() bool {
	return (ap&0xF0 == 0x00) || (ap&0x0F == 0x00)
}

func (ap AddressFamilyAndProtocol) toByte() byte {
	if ap.IsIPv4() && ap.IsStream() {
		return byte(TCPv4)
	} else if ap.IsIPv4() && ap.IsDatagram() {
		return byte(UDPv4)
	} else if ap.IsIPv6() && ap.IsStream() {
		return byte(TCPv6)
	} else if ap.IsIPv6() && ap.IsDatagram() {
		return byte(UDPv6)
	} else if ap.IsUnix() && ap.IsStream() {
		return byte(UnixStream)
	} else if ap.IsUnix() && ap.IsDatagram() {
		return byte(UnixDatagram)
	}

	return byte(UNSPEC)
}
<|endoftext|>


<commit_before>package admin

import (
	"path"

	"github.com/bom-d-van/goutils/printutils"
)

type Menu struct {
	Name   string
	params string
	Link   string
	Items  []*Menu
}

func (admin Admin) GetMenus() []*Menu {
	printutils.PrettyPrint(admin.menus)
	return admin.menus
}

func (admin Admin) GetMenu(name string) (m *Menu) {
	return getMenu(admin.menus, name)
}

func getMenu(menus []*Menu, name string) *Menu {
	for _, m := range menus {
		if m.Name == name {
			return m
		}

		if len(m.Items) > 0 {
			if mc := getMenu(m.Items, name); mc != nil {
				return mc
			}
		}
	}

	return nil
}

func (admin *Admin) AddMenu(menu *Menu) {
	admin.menus = append(admin.menus, menu)
}

func (admin *Admin) linkMenus() {
	relinkMenus(admin.menus, admin.router.Prefix)
}

func relinkMenus(menus []*Menu, prefix string) {
	for _, m := range menus {
		if m.params != "" {
			m.Link = path.Join(prefix, m.params)
		}
		if len(m.Items) > 0 {
			relinkMenus(m.Items, prefix)
		}
	}
}

func (m *Menu) AddChild(menu *Menu) {
	m.Items = append(m.Items, menu)
}

func newMenu(menus []string, res *Resource) (m *Menu) {
	if mlen := len(menus); mlen == 0 {
		m = &Menu{params: res.ToParam(), Name: res.Name}
	} else {
		m = &Menu{
			Name:  menus[0],
			Items: []*Menu{&Menu{params: res.ToParam(), Name: res.Name}},
		}

		for i := mlen - 2; i >= 0; i-- {
			m = &Menu{
				Name:  menus[i],
				Items: []*Menu{m},
			}
		}
	}

	return
}

func appendMenu(menus []*Menu, resMenus []string, res *Resource) []*Menu {
	if len(resMenus) == 0 {
		return append(menus, newMenu(resMenus, res))
	}

	for _, m := range menus {
		if m.Link != "" {
			continue
		}

		if m.Name != resMenus[0] {
			continue
		}

		if len(resMenus) > 1 {
			m.Items = appendMenu(m.Items, resMenus[1:], res)
		} else {
			m.Items = append(m.Items, newMenu(nil, res))
		}
		return menus
	}

	return append(menus, newMenu(resMenus, res))
}
<commit_msg>admin: remove debug logs<commit_after>package admin

import "path"

type Menu struct {
	Name   string
	params string
	Link   string
	Items  []*Menu
}

func (admin Admin) GetMenus() []*Menu {
	return admin.menus
}

func (admin Admin) GetMenu(name string) (m *Menu) {
	return getMenu(admin.menus, name)
}

func getMenu(menus []*Menu, name string) *Menu {
	for _, m := range menus {
		if m.Name == name {
			return m
		}

		if len(m.Items) > 0 {
			if mc := getMenu(m.Items, name); mc != nil {
				return mc
			}
		}
	}

	return nil
}

func (admin *Admin) AddMenu(menu *Menu) {
	admin.menus = append(admin.menus, menu)
}

func (admin *Admin) linkMenus() {
	relinkMenus(admin.menus, admin.router.Prefix)
}

func relinkMenus(menus []*Menu, prefix string) {
	for _, m := range menus {
		if m.params != "" {
			m.Link = path.Join(prefix, m.params)
		}
		if len(m.Items) > 0 {
			relinkMenus(m.Items, prefix)
		}
	}
}

func (m *Menu) AddChild(menu *Menu) {
	m.Items = append(m.Items, menu)
}

func newMenu(menus []string, res *Resource) (m *Menu) {
	if mlen := len(menus); mlen == 0 {
		m = &Menu{params: res.ToParam(), Name: res.Name}
	} else {
		m = &Menu{
			Name:  menus[0],
			Items: []*Menu{&Menu{params: res.ToParam(), Name: res.Name}},
		}

		for i := mlen - 2; i >= 0; i-- {
			m = &Menu{
				Name:  menus[i],
				Items: []*Menu{m},
			}
		}
	}

	return
}

func appendMenu(menus []*Menu, resMenus []string, res *Resource) []*Menu {
	if len(resMenus) == 0 {
		return append(menus, newMenu(resMenus, res))
	}

	for _, m := range menus {
		if m.Link != "" {
			continue
		}

		if m.Name != resMenus[0] {
			continue
		}

		if len(resMenus) > 1 {
			m.Items = appendMenu(m.Items, resMenus[1:], res)
		} else {
			m.Items = append(m.Items, newMenu(nil, res))
		}
		return menus
	}

	return append(menus, newMenu(resMenus, res))
}
<|endoftext|>


<commit_before>package grim

// Copyright 2015 MediaMath <http://www.mediamath.com>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

import (
	"bufio"
	"fmt"
	"io"
	"os/exec"
	"sync"
	"syscall"
	"time"
)

type eitherStringOrError struct {
	str string
	err error
}

func execute(env []string, workingDir string, execPath string, args ...string) (*executeResult, error) {
	outputChan := make(chan string)

	res, err := executeWithOutputChan(outputChan, env, workingDir, execPath, args...)
	if err != nil {
		return nil, err
	}

	out := ""
	for line := range outputChan {
		out += fmt.Sprintf("%v\n", line)
	}

	res.Output = out

	return res, nil
}

func executeWithOutputChan(outputChan chan string, env []string, workingDir string, execPath string, args ...string) (*executeResult, error) {
	var exitCode int

	startTime := time.Now()

	cmd := exec.Command(execPath, args...)
	cmd.Dir = workingDir
	cmd.Env = env

	var startErr error

	var wg sync.WaitGroup

	outReader, orErr := cmd.StdoutPipe()
	if orErr != nil {
		return nil, fmt.Errorf("error capturing stdout: %v", orErr)
	}

	errReader, erErr := cmd.StderrPipe()
	if erErr != nil {
		return nil, fmt.Errorf("error capturing stderr: %v", erErr)
	}

	wg.Add(2)
	go sendLines(outReader, outputChan, &wg)
	go sendLines(errReader, outputChan, &wg)
	go closeAfterDone(outputChan, &wg)

	startErr = cmd.Start()
	if startErr != nil {
		return nil, fmt.Errorf("error starting process: %v", startErr)
	}

	//create a new effectiveconfig instance
	var con = new(effectiveConfig)
	done := make(chan error, 1)
	go func() {
		done <- cmd.Wait()
	}()
	select {
	case <-time.After(con.BuildTimeout()):
		if err := cmd.Process.Kill(); err != nil {
			return nil, fmt.Errorf("Failed to kill process: ", err)
		}
		<-done
	case err := <-done:
		if err != nil {
			if exitErr, ok := cmd.Wait().(*exec.ExitError); ok {
				if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
					exitCode = status.ExitStatus()
				}
			}

			return nil, fmt.Errorf("Process done with error = %v", err)
		}
	}

	return &executeResult{
		StartTime:  startTime,
		EndTime:    time.Now(),
		SysTime:    cmd.ProcessState.SystemTime(),
		UserTime:   cmd.ProcessState.UserTime(),
		InitialEnv: cmd.Env,
		ExitCode:   exitCode,
	}, nil
}

func sendLines(rc io.ReadCloser, linesChan chan string, wg *sync.WaitGroup) {
	scanner := bufio.NewScanner(rc)
	for scanner.Scan() {
		linesChan <- scanner.Text()
	}
	wg.Done()
}

func closeAfterDone(outputChan chan string, wg *sync.WaitGroup) {
	wg.Wait()
	close(outputChan)
}
<commit_msg>fixed an Errorf call that was not failing on local but on grim<commit_after>package grim

// Copyright 2015 MediaMath <http://www.mediamath.com>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

import (
	"bufio"
	"fmt"
	"io"
	"os/exec"
	"sync"
	"syscall"
	"time"
)

type eitherStringOrError struct {
	str string
	err error
}

func execute(env []string, workingDir string, execPath string, args ...string) (*executeResult, error) {
	outputChan := make(chan string)

	res, err := executeWithOutputChan(outputChan, env, workingDir, execPath, args...)
	if err != nil {
		return nil, err
	}

	out := ""
	for line := range outputChan {
		out += fmt.Sprintf("%v\n", line)
	}

	res.Output = out

	return res, nil
}

func executeWithOutputChan(outputChan chan string, env []string, workingDir string, execPath string, args ...string) (*executeResult, error) {
	var exitCode int

	startTime := time.Now()

	cmd := exec.Command(execPath, args...)
	cmd.Dir = workingDir
	cmd.Env = env

	var startErr error

	var wg sync.WaitGroup

	outReader, orErr := cmd.StdoutPipe()
	if orErr != nil {
		return nil, fmt.Errorf("error capturing stdout: %v", orErr)
	}

	errReader, erErr := cmd.StderrPipe()
	if erErr != nil {
		return nil, fmt.Errorf("error capturing stderr: %v", erErr)
	}

	wg.Add(2)
	go sendLines(outReader, outputChan, &wg)
	go sendLines(errReader, outputChan, &wg)
	go closeAfterDone(outputChan, &wg)

	startErr = cmd.Start()
	if startErr != nil {
		return nil, fmt.Errorf("error starting process: %v", startErr)
	}

	//create a new effectiveconfig instance
	var con = new(effectiveConfig)
	done := make(chan error, 1)
	go func() {
		done <- cmd.Wait()
	}()
	select {
	case <-time.After(con.BuildTimeout()):
		if err := cmd.Process.Kill(); err != nil {
			return nil, fmt.Errorf("Failed to kill process: %v", err)
		}
		<-done
	case err := <-done:
		if err != nil {
			if exitErr, ok := cmd.Wait().(*exec.ExitError); ok {
				if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
					exitCode = status.ExitStatus()
				}
			}

			return nil, fmt.Errorf("Process done with error = %v", err)
		}
	}

	return &executeResult{
		StartTime:  startTime,
		EndTime:    time.Now(),
		SysTime:    cmd.ProcessState.SystemTime(),
		UserTime:   cmd.ProcessState.UserTime(),
		InitialEnv: cmd.Env,
		ExitCode:   exitCode,
	}, nil
}

func sendLines(rc io.ReadCloser, linesChan chan string, wg *sync.WaitGroup) {
	scanner := bufio.NewScanner(rc)
	for scanner.Scan() {
		linesChan <- scanner.Text()
	}
	wg.Done()
}

func closeAfterDone(outputChan chan string, wg *sync.WaitGroup) {
	wg.Wait()
	close(outputChan)
}
<|endoftext|>


<commit_before>package core

//go:generate go install google.golang.org/protobuf/proto
//go:generate go install google.golang.org/protobuf/cmd/protoc-gen-go
//go:generate go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
//go:generate go install github.com/gogo/protobuf/protoc-gen-gofast
//go:generate go run v2ray.com/core/infra/vprotogen
<commit_msg>Refine & make proto.go work outside GOPATH<commit_after>package core

//go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go
//go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc
//go:generate go install -v github.com/gogo/protobuf/protoc-gen-gofast
//go:generate go run ./infra/vprotogen/main.go
<|endoftext|>


<commit_before>package gorange

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

// ProxyConfig specifies the configuration for a gorange proxy HTTP server.
type ProxyConfig struct {
	// CheckVersionPeriodicity directs the range proxy to periodically send the '%version' query
	// the proxied range servers, and if the value is greater than the previous value, to
	// asynchronously update all the values for recently used range keys.
	CheckVersionPeriodicity time.Duration

	// Log directs the proxy to emit common log formatted log lines to the specified io.Writer.
	Log io.Writer

	// Port specifies which network port the proxy should bind to.
	Port uint

	// Servers specifies which addresses ought to be consulted as the source of truth for range
	// queries.
	Servers []string

	// Timeout specifies how long to wait for the source of truth to respond. If the zero-value,
	// no timeout will be used. Not having a timeout value may cause resource exhaustion where
	// any of the proxied servers take too long to return a response.
	Timeout time.Duration
}

// Proxy creates a proxy http server on the port that proxies range queries to the specified range
// servers.
func Proxy(config ProxyConfig) error {
	querier, err := NewQuerier(&Configurator{
		CheckVersionPeriodicity: config.CheckVersionPeriodicity,
		RetryCount:              len(config.Servers),
		Servers:                 config.Servers,
	})
	if err != nil {
		return err
	}

	mux := http.NewServeMux()
	mux.Handle("/range/expand", onlyGet(decodeURI(expand(querier))))
	mux.Handle("/range/list", onlyGet(decodeURI(list(querier))))
	mux.Handle("/", notFound())

	h := PanicHandler(mux)
	if config.Timeout > 0 {
		h = http.TimeoutHandler(h, config.Timeout, "request took too long")
	}
	if config.Log != nil {
		h = ErrorLogHandler(h, config.Log)
		// h = LogHandler(h, config.Log)
	}

	server := http.Server{
		Addr:         fmt.Sprintf(":%d", config.Port),
		Handler:      h,
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 15 * time.Second,
	}
	return server.ListenAndServe()
}

func httpError(w http.ResponseWriter, text string, code int) {
	fullText := strconv.Itoa(code) + " " + http.StatusText(code)
	if text != "" {
		fullText += ": " + text
	}
	http.Error(w, fullText, code)
}

func notFound() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		httpError(w, fmt.Sprintf("%v", r.URL), http.StatusNotFound)
	})
}

func onlyGet(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "GET" {
			httpError(w, r.Method, http.StatusMethodNotAllowed)
			return
		}
		next.ServeHTTP(w, r)
	})
}

type key int

const requestIDKey key = 0

func contextFromQuery(ctx context.Context, r *http.Request) (context.Context, error) {
	query, err := url.QueryUnescape(r.URL.RawQuery)
	if err != nil {
		return nil, fmt.Errorf("cannot decode query: " + err.Error())
	}
	return context.WithValue(ctx, requestIDKey, query), nil
}

func queryFromContext(ctx context.Context) string {
	return ctx.Value(requestIDKey).(string)
}

func decodeURI(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx, err := contextFromQuery(r.Context(), r)
		if err != nil {
			httpError(w, err.Error(), http.StatusBadRequest)
			return
		}
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

func expand(querier Querier) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		query := queryFromContext(r.Context())
		response, err := querier.Expand(query)
		if err != nil {
			httpError(w, "cannot resolve query: "+err.Error(), http.StatusBadGateway)
			return
		}
		if _, err = io.WriteString(w, response); err != nil {
			httpError(w, "cannot write response: "+err.Error(), http.StatusInternalServerError)
			return
		}
	})
}

func list(querier Querier) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		query := queryFromContext(r.Context())
		responses, err := querier.List(query)
		if err != nil {
			httpError(w, "cannot resolve query: "+err.Error(), http.StatusBadGateway)
			return
		}
		for _, response := range responses {
			if _, err = fmt.Fprintf(w, "%s\r\n", response); err != nil {
				httpError(w, "cannot write response: "+err.Error(), http.StatusInternalServerError)
				return
			}
		}
	})
}

// ErrorLogHandler returns a new http.Handler that logs HTTP requests that result in response
// errors. The handler will output lines in common log format to the specified io.Writer.
func ErrorLogHandler(next http.Handler, out io.Writer) http.Handler {
	const apacheLogFormat = "%s [%s] \"%s\" %d %d %f\n"
	const timeFormat = "02/Jan/2006:15:04:05 MST"

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		lrw := &loggedResponseWriter{
			ResponseWriter: w,
			status:         http.StatusOK,
		}

		begin := time.Now()
		next.ServeHTTP(lrw, r)

		if lrw.status != http.StatusOK {
			end := time.Now()
			clientIP := r.RemoteAddr
			if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
				clientIP = clientIP[:colon]
			}
			request := fmt.Sprintf("%s %s %s", r.Method, r.RequestURI, r.Proto)
			duration := end.Sub(begin).Seconds()
			formattedTime := end.UTC().Format(timeFormat)
			fmt.Fprintf(out, apacheLogFormat, clientIP, formattedTime, request, lrw.status, lrw.responseBytes, duration)
		}
	})
}

// LogHandler returns a new http.Handler that logs HTTP requests and responses in common log format
// to the specified io.Writer.
func LogHandler(next http.Handler, out io.Writer) http.Handler {
	const apacheLogFormat = "%s [%s] \"%s\" %d %d %f\n"
	const timeFormat = "02/Jan/2006:15:04:05 MST"

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		lrw := &loggedResponseWriter{
			ResponseWriter: w,
			status:         http.StatusOK,
		}

		begin := time.Now()
		next.ServeHTTP(lrw, r)
		end := time.Now()

		clientIP := r.RemoteAddr
		if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
			clientIP = clientIP[:colon]
		}
		request := fmt.Sprintf("%s %s %s", r.Method, r.RequestURI, r.Proto)

		duration := end.Sub(begin).Seconds()
		formattedTime := end.UTC().Format(timeFormat)
		fmt.Fprintf(out, apacheLogFormat, clientIP, formattedTime, request, lrw.status, lrw.responseBytes, duration)
	})
}

type loggedResponseWriter struct {
	http.ResponseWriter
	responseBytes int64
	status        int
}

func (r *loggedResponseWriter) Write(p []byte) (int, error) {
	written, err := r.ResponseWriter.Write(p)
	r.responseBytes += int64(written)
	return written, err
}

func (r *loggedResponseWriter) WriteHeader(status int) {
	r.status = status
	r.ResponseWriter.WriteHeader(status)
}

// PanicHandler returns a new http.Handler that catches a panic caused by the specified
// http.Handler, and responds with an appropriate http status code and message.
func PanicHandler(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if r := recover(); r != nil {
				var text string
				switch t := r.(type) {
				case error:
					text = t.Error()
				case string:

				default:
					text = fmt.Sprintf("%v", r)
				}
				httpError(w, text, http.StatusInternalServerError)
			}
		}()
		next.ServeHTTP(w, r)
	})
}
<commit_msg>uses gohm for HTTP handler middleware<commit_after>package gorange

import (
	"context"
	"expvar"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"time"

	"github.com/karrick/gohm"
)

var errorCount = expvar.NewInt("errorCount")

// ProxyConfig specifies the configuration for a gorange proxy HTTP server.
type ProxyConfig struct {
	// CheckVersionPeriodicity directs the range proxy to periodically send the '%version' query
	// the proxied range servers, and if the value is greater than the previous value, to
	// asynchronously update all the values for recently used range keys.
	CheckVersionPeriodicity time.Duration

	// Log directs the proxy to emit common log formatted log lines to the specified io.Writer.
	Log io.Writer

	// Port specifies which network port the proxy should bind to.
	Port uint

	// Servers specifies which addresses ought to be consulted as the source of truth for range
	// queries.
	Servers []string

	// Timeout specifies how long to wait for the source of truth to respond. If the zero-value,
	// no timeout will be used. Not having a timeout value may cause resource exhaustion where
	// any of the proxied servers take too long to return a response.
	Timeout time.Duration
}

// Proxy creates a proxy http server on the port that proxies range queries to the specified range
// servers.
func Proxy(config ProxyConfig) error {
	querier, err := NewQuerier(&Configurator{
		CheckVersionPeriodicity: config.CheckVersionPeriodicity,
		RetryCount:              len(config.Servers),
		Servers:                 config.Servers,
	})
	if err != nil {
		return err
	}

	mux := http.NewServeMux()
	mux.Handle("/range/expand", onlyGet(decodeURI(expand(querier))))
	mux.Handle("/range/list", onlyGet(decodeURI(list(querier))))
	mux.Handle("/", notFound())

	var h http.Handler = mux
	if config.Timeout > 0 {
		h = http.TimeoutHandler(h, config.Timeout, "took too long to process request")
	}
	h = gohm.PanicHandler(mux)
	h = gohm.ErrorCountHandler(errorCount, h)
	if config.Log != nil {
		h = gohm.ErrorLogHandler(config.Log, h)
		// h = gohm.LogHandler(config.Log, h)
	}

	server := http.Server{
		Addr:         fmt.Sprintf(":%d", config.Port),
		Handler:      h,
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 15 * time.Second,
	}
	return server.ListenAndServe()
}

func notFound() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		gohm.Error(w, fmt.Sprintf("%v", r.URL), http.StatusNotFound)
	})
}

func onlyGet(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "GET" {
			gohm.Error(w, r.Method, http.StatusMethodNotAllowed)
			return
		}
		next.ServeHTTP(w, r)
	})
}

type key int

const requestIDKey key = 0

func contextFromQuery(ctx context.Context, r *http.Request) (context.Context, error) {
	query, err := url.QueryUnescape(r.URL.RawQuery)
	if err != nil {
		return nil, fmt.Errorf("cannot decode query: %s", err)
	}
	return context.WithValue(ctx, requestIDKey, query), nil
}

func queryFromContext(ctx context.Context) string {
	return ctx.Value(requestIDKey).(string)
}

func decodeURI(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx, err := contextFromQuery(r.Context(), r)
		if err != nil {
			gohm.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

func expand(querier Querier) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		query := queryFromContext(r.Context())
		response, err := querier.Expand(query)
		if err != nil {
			gohm.Error(w, "cannot resolve query: "+err.Error(), http.StatusBadGateway)
			return
		}
		if _, err = io.WriteString(w, response); err != nil {
			gohm.Error(w, "cannot write response: "+err.Error(), http.StatusInternalServerError)
			return
		}
	})
}

func list(querier Querier) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		query := queryFromContext(r.Context())
		responses, err := querier.List(query)
		if err != nil {
			gohm.Error(w, "cannot resolve query: "+err.Error(), http.StatusBadGateway)
			return
		}
		for _, response := range responses {
			if _, err = fmt.Fprintf(w, "%s\r\n", response); err != nil {
				gohm.Error(w, "cannot write response: "+err.Error(), http.StatusInternalServerError)
				return
			}
		}
	})
}
<|endoftext|>


<commit_before>package cafs

import (
	"bytes"
	"crypto/sha1"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"sync"

	"github.com/tchaik/tchaik/store"
)

// Index is an interface which contains methods for implementing
// a content addressable file system.
type Index interface {
	// Get returns the real path for the given filename, with true if and only
	// if the path exists in the index.
	Get(path string) (string, bool)

	// Add adds the path to the index, and returns the path to the file
	// and whether the path/content already exists.
	Add(path string, sum string) (bool, error)

	// Exists returns true of the sum is in the index.
	Exists(sum string) bool
}

type index struct {
	sync.RWMutex

	files map[string]string // path -> sha1
	index map[string]bool   // {sha1}

	fs store.RWFileSystem
}

// NewIndex creates a new file system index.
func NewIndex(fs store.RWFileSystem) (*index, error) {
	idx := &index{
		files: make(map[string]string),
		index: make(map[string]bool),
		fs:    fs,
	}

	f, err := fs.Open("index.json")
	if err != nil {
		// FIXME: Improve this
		// Can't guarantee that we will get an IsNotExist(err) here
		return idx, nil
	}
	defer f.Close()

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, fmt.Errorf("error reading index: %v", err)
	}
	err = json.Unmarshal(b, idx)
	if err != nil {
		return nil, fmt.Errorf("error decoding index: %v", err)
	}
	fmt.Printf("Index initialised: %d files (%d paths)", len(idx.index), len(idx.files))
	return idx, nil
}

func (i *index) MarshalJSON() ([]byte, error) {
	i.RLock()
	defer i.RUnlock()

	exp := struct {
		Files map[string]string `json:"files"`
	}{
		Files: i.files,
	}
	return json.Marshal(exp)
}

func (i *index) UnmarshalJSON(b []byte) error {
	i.Lock()
	defer i.Unlock()

	var exp struct {
		Files map[string]string
	}
	err := json.Unmarshal(b, &exp)
	if err != nil {
		return err
	}

	i.files = make(map[string]string)
	i.index = make(map[string]bool)
	for k, v := range exp.Files {
		i.index[v] = true
		i.files[k] = v
	}
	return nil
}

// Get implements Index.
func (i *index) Get(path string) (string, bool) {
	i.RLock()
	defer i.RUnlock()

	x, ok := i.files[path]
	return x, ok
}

// Add implements Index.
func (i *index) Add(path, sum string) (bool, error) {
	i.Lock()
	defer i.Unlock()

	i.files[path] = sum
	old := i.index[sum]
	i.index[sum] = true
	return old, i.persist()
}

// Exists implements Index.
func (i *index) Exists(sum string) bool {
	i.RLock()
	defer i.RUnlock()

	return i.index[sum]
}

func (i *index) persist() error {
	f, err := i.fs.Create("index.json")
	if err != nil {
		return fmt.Errorf("error creating index: %v", err)
	}
	defer f.Close()

	b, err := json.Marshal(i)
	if err != nil {
		return fmt.Errorf("error encoding index: %v", err)
	}

	_, err = f.Write(b)
	if err != nil {
		return fmt.Errorf("error writing index: %v", err)
	}
	return nil
}

// Add the path+data to the index.  Returns the content sum and true if the content
// already existed in the index, false otherwise.
func AddContent(idx Index, path string, content []byte) (string, bool, error) {
	if x, ok := idx.Get(path); ok {
		return x, true, nil
	}
	s := fmt.Sprintf("%x", sha1.Sum(content))
	ok, err := idx.Add(path, s)
	return s, ok, err
}

// FileSystem is a type which defines a content addressable filesystem.
type FileSystem struct {
	idx Index

	fs store.RWFileSystem
}

// Open the file with the given path.  Uses the internal index to identify
// which file to open.  NB: Stat on the returned file will refer to the
// internal file.
func (s *FileSystem) Open(path string) (http.File, error) {
	realPath, ok := s.idx.Get(path)
	if !ok {
		return nil, fmt.Errorf("no such file: %v", path)
	}
	return s.open(realPath)
}

// Wait implements RWFileSystem.
func (s *FileSystem) Wait() error { return nil }

func (s *FileSystem) open(path string) (http.File, error) {
	return s.fs.Open("content/" + path)
}

func (s *FileSystem) create(path string) (io.WriteCloser, error) {
	return s.fs.Create("content/" + path)
}

type file struct {
	bytes.Buffer

	fs   *FileSystem
	path string
}

// Close acts as a signal that all the information has been written to
// the underlying buffer, and the file can be written to the RWFileSystem.
func (a *file) Close() error {
	_, ok := a.fs.idx.Get(a.path)
	if ok {
		return fmt.Errorf("file already exists: %v", a.path)
	}

	path, ok, err := AddContent(a.fs.idx, a.path, a.Bytes())
	if !ok {
		fmt.Println("creating", path)
		f, err := a.fs.create(path)
		if err != nil {
			return fmt.Errorf("error creating file: %v", err)
		}
		defer f.Close()
		_, err = io.Copy(f, a)
		if err != nil {
			return fmt.Errorf("error copying data into file '%v': %v", path, err)
		}
	}
	return err
}

// Create a new file with path. We buffer the contents written to the io.WriteCloser
// so that the content can be hashed and then written to the underlying RWFileSystem.
func (s *FileSystem) Create(path string) (io.WriteCloser, error) {
	_, ok := s.idx.Get(path)
	if ok {
		return nil, fmt.Errorf("file already exists for '%v'", path)
	}

	return &file{
		Buffer: bytes.Buffer{},
		path:   path,
		fs:     s,
	}, nil
}

// New creates a new content addressable RWFileSystem.
func New(fs store.RWFileSystem) (*FileSystem, error) {
	idx, err := NewIndex(fs)
	if err != nil {
		return nil, err
	}
	return &FileSystem{
		idx: idx,
		fs:  fs,
	}, nil
}
<commit_msg>Finish CAFS refactor.<commit_after>package cafs

import (
	"bytes"
	"crypto/sha1"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"sync"

	"github.com/tchaik/tchaik/store"
)

// Index is an interface which contains methods for implementing
// a content addressable file system.
type Index interface {
	// Get returns the real path for the given filename, with true if and only
	// if the path exists in the index.
	Get(path string) (string, bool)

	// Add adds the path to the index, and returns the path to the file
	// and whether the path/content already exists.
	Add(path string, sum string) (bool, error)

	// Exists returns true of the sum is in the index.
	Exists(sum string) bool
}

type index struct {
	sync.RWMutex

	files map[string]string // path -> sha1
	index map[string]bool   // {sha1}

	fs store.RWFileSystem
}

// NewIndex creates a new file system index.
func NewIndex(fs store.RWFileSystem) (*index, error) {
	idx := &index{
		files: make(map[string]string),
		index: make(map[string]bool),
		fs:    fs,
	}

	f, err := fs.Open("index.json")
	if err != nil {
		// FIXME: Improve this
		// Can't guarantee that we will get an IsNotExist(err) here
		return idx, nil
	}
	defer f.Close()

	dec := json.NewDecoder(f)
	err = dec.Decode(&idx)
	if err != nil {
		if err == io.EOF {
			return idx, nil
		}
		return nil, fmt.Errorf("error decoding index: %v", err)
	}
	fmt.Printf("Index initialised: %d files (%d paths)", len(idx.index), len(idx.files))
	return idx, nil
}

func (i *index) UnmarshalJSON(b []byte) error {
	i.Lock()
	defer i.Unlock()

	var exp struct {
		Files map[string]string
	}
	err := json.Unmarshal(b, &exp)
	if err != nil {
		return err
	}

	i.files = make(map[string]string)
	i.index = make(map[string]bool)
	for k, v := range exp.Files {
		i.index[v] = true
		i.files[k] = v
	}
	return nil
}

// Get implements Index.
func (i *index) Get(path string) (string, bool) {
	i.RLock()
	defer i.RUnlock()

	x, ok := i.files[path]
	return x, ok
}

// Add implements Index.
func (i *index) Add(path, sum string) (bool, error) {
	i.Lock()
	defer i.Unlock()

	i.files[path] = sum
	old := i.index[sum]
	i.index[sum] = true
	return old, i.persist()
}

// Exists implements Index.
func (i *index) Exists(sum string) bool {
	i.RLock()
	defer i.RUnlock()

	return i.index[sum]
}

func (i *index) persist() error {
	f, err := i.fs.Create("index.json")
	if err != nil {
		return fmt.Errorf("error creating index: %v", err)
	}
	defer f.Close()

	exp := struct {
		Files map[string]string `json:"files"`
	}{
		Files: i.files,
	}

	b, err := json.Marshal(exp)
	if err != nil {
		return fmt.Errorf("error encoding index: %v", err)
	}

	_, err = f.Write(b)
	if err != nil {
		return fmt.Errorf("error writing index: %v", err)
	}
	return nil
}

// Add the path+data to the index.  Returns the content sum and true if the content
// already existed in the index, false otherwise.
func AddContent(idx Index, path string, content []byte) (string, bool, error) {
	if x, ok := idx.Get(path); ok {
		return x, true, nil
	}
	s := fmt.Sprintf("%x", sha1.Sum(content))
	ok, err := idx.Add(path, s)
	return s, ok, err
}

// FileSystem is a type which defines a content addressable filesystem.
type FileSystem struct {
	idx Index

	fs store.RWFileSystem
}

// Open the file with the given path.  Uses the internal index to identify
// which file to open.  NB: Stat on the returned file will refer to the
// internal file.
func (s *FileSystem) Open(path string) (http.File, error) {
	realPath, ok := s.idx.Get(path)
	if !ok {
		return nil, fmt.Errorf("no such file: %v", path)
	}
	return s.open(realPath)
}

// Wait implements RWFileSystem.
func (s *FileSystem) Wait() error { return nil }

func (s *FileSystem) open(path string) (http.File, error) {
	return s.fs.Open("content/" + path)
}

func (s *FileSystem) create(path string) (io.WriteCloser, error) {
	return s.fs.Create("content/" + path)
}

type file struct {
	bytes.Buffer

	fs   *FileSystem
	path string
}

// Close acts as a signal that all the information has been written to
// the underlying buffer, and the file can be written to the RWFileSystem.
func (a *file) Close() error {
	_, ok := a.fs.idx.Get(a.path)
	if ok {
		return fmt.Errorf("file already exists: %v", a.path)
	}

	path, ok, err := AddContent(a.fs.idx, a.path, a.Bytes())
	if !ok {
		fmt.Println("creating", path)
		f, err := a.fs.create(path)
		if err != nil {
			return fmt.Errorf("error creating file: %v", err)
		}
		defer f.Close()
		_, err = io.Copy(f, a)
		if err != nil {
			return fmt.Errorf("error copying data into file '%v': %v", path, err)
		}
	}
	return err
}

// Create a new file with path. We buffer the contents written to the io.WriteCloser
// so that the content can be hashed and then written to the underlying RWFileSystem.
func (s *FileSystem) Create(path string) (io.WriteCloser, error) {
	_, ok := s.idx.Get(path)
	if ok {
		return nil, fmt.Errorf("file already exists for '%v'", path)
	}

	return &file{
		Buffer: bytes.Buffer{},
		path:   path,
		fs:     s,
	}, nil
}

// New creates a new content addressable RWFileSystem.
func New(fs store.RWFileSystem) (*FileSystem, error) {
	idx, err := NewIndex(fs)
	if err != nil {
		return nil, err
	}
	return &FileSystem{
		idx: idx,
		fs:  fs,
	}, nil
}
<|endoftext|>


<commit_before>package repo

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"testing"

	"github.com/sahib/brig/util/testutil"
	"github.com/stretchr/testify/require"
)

func mustCreate(t *testing.T, path string, size int64) []byte {
	if err := os.MkdirAll(filepath.Dir(path), 0744); err != nil {
		t.Fatalf("Failed to create necessary directories for %v: %v", path, err)
	}

	fd, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
	if err != nil {
		t.Fatalf("Failed to touch `%s`: %v", path, err)
	}

	buf := testutil.CreateDummyBuf(size)
	if _, err := fd.Write(buf); err != nil {
		t.Fatalf("Failed to write dummy data to %s: %v", path, err)
	}

	if err := fd.Close(); err != nil {
		t.Fatalf("Failed to close fd for `%s`: %v", path, err)
	}
	return buf
}

func withTempDir(t *testing.T, fn func(dir string)) {
	dir, err := ioutil.TempDir("", "brig-repo-test-")
	if err != nil {
		t.Fatalf("Failed to create temp dir: %v", err)
	}

	fn(dir)

	if err := os.RemoveAll(dir); err != nil {
		t.Fatalf("Failed to remove test directory at `%s`: %v", dir, err)
	}
}

func TestLockFile(t *testing.T) {
	withTempDir(t, func(dir string) {
		xData := mustCreate(t, filepath.Join(dir, "x"), 0)
		yData := mustCreate(t, filepath.Join(dir, "y"), 1024)
		zData := mustCreate(t, filepath.Join(dir, "z"), 1024*1024)

		// Do not lock this file:
		mustCreate(t, filepath.Join(dir, "meta.yml"), 1024)

		subDir := filepath.Join(dir, "sub")
		if err := os.Mkdir(subDir, 0744); err != nil {
			t.Fatalf("Creating test sub dir failed: %v", err)
		}

		aData := mustCreate(t, filepath.Join(subDir, "a"), 2*1024*1024)

		// Should be overwritten.
		mustCreate(t, filepath.Join(dir, "z.locked"), 2)

		excludes := []string{"meta.yml"}
		if err := LockRepo(dir, "karl", "klaus", excludes); err != nil {
			t.Fatalf("Failed to lock directory: %v", err)
		}

		err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
			if path == dir || strings.HasSuffix(path, "meta.yml") {
				return nil
			}

			if !strings.HasSuffix(path, LockPathSuffix) && path != dir {
				t.Fatalf("%s has not been locked", path)
			}

			return nil
		})

		if err != nil {
			t.Fatalf("walk failed: %v", err)
		}

		// Try with a wrong password:
		if err := UnlockRepo(dir, "karl", "klausi", excludes); err == nil {
			t.Fatalf("unlock worked without correct password")
		}

		// Try with a wrong user:
		if err := UnlockRepo(dir, "karol", "klaus", excludes); err == nil {
			t.Fatalf("unlock worked without correct user")
		}

		if err := UnlockRepo(dir, "karl", "klaus", excludes); err != nil {
			t.Fatalf("unlock failed: %v", err)
		}

		err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
			if strings.HasSuffix(path, LockPathSuffix) && path != dir {
				t.Fatalf("%s is still locked", path)
			}

			cmp := func(expected []byte) {
				data, err := ioutil.ReadFile(path)
				if err != nil {
					t.Fatalf("Failed to read file %s: %v", path, err)
				}

				if !bytes.Equal(expected, data) {
					t.Fatalf("Content differs after lock & unlock: %s", path)
				}
			}

			switch filepath.Base(path) {
			case "a":
				cmp(aData)
			case "x":
				cmp(xData)
			case "y":
				cmp(yData)
			case "z":
				cmp(zData)
			}

			return nil
		})

		if err != nil {
			t.Fatalf("walk after unlock failed: %v", err)
		}

	})
}

func TestLockDirectory(t *testing.T) {
	withTempDir(t, func(dir string) {
		mustCreate(t, filepath.Join(dir, "a/b/x"), 1024)
		mustCreate(t, filepath.Join(dir, "a/b/empty_file"), 0)
		mustCreate(t, filepath.Join(dir, "a/x"), 1024)
		mustCreate(t, filepath.Join(dir, "x"), 1024)

		require.Nil(t, os.MkdirAll(filepath.Join(dir, "empty"), 0744))

		key := make([]byte, 32)
		require.Nil(t, lockDirectory(dir, key))
		require.Nil(t, os.RemoveAll(dir))
		require.Nil(t, unlockDirectory(dir+".tgz.locked", key))

		paths := []string{}
		walker := func(path string, child os.FileInfo, err error) error {
			require.Nil(t, err)
			path = path[len(dir):]
			if len(path) > 0 {
				paths = append(paths, path)
			}

			return nil
		}

		require.Nil(t, filepath.Walk(dir, walker))

		sort.Strings(paths)

		// Note that /empty vanished after untarring.
		// For now we do not support tarring empty directories.
		require.Equal(
			t,
			[]string{
				"/a",
				"/a/b",
				"/a/b/empty_file",
				"/a/b/x",
				"/a/x",
				"/x",
			},
			paths,
		)
	})
}
<commit_msg>repo: fix {un,}lock tests<commit_after>package repo

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"testing"

	"github.com/sahib/brig/util/testutil"
	"github.com/stretchr/testify/require"
)

func mustCreate(t *testing.T, path string, size int64) []byte {
	if err := os.MkdirAll(filepath.Dir(path), 0744); err != nil {
		t.Fatalf("Failed to create necessary directories for %v: %v", path, err)
	}

	fd, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
	if err != nil {
		t.Fatalf("Failed to touch `%s`: %v", path, err)
	}

	buf := testutil.CreateDummyBuf(size)
	if _, err := fd.Write(buf); err != nil {
		t.Fatalf("Failed to write dummy data to %s: %v", path, err)
	}

	if err := fd.Close(); err != nil {
		t.Fatalf("Failed to close fd for `%s`: %v", path, err)
	}
	return buf
}

func withTempDir(t *testing.T, fn func(dir string)) {
	dir, err := ioutil.TempDir("", "brig-repo-test-")
	if err != nil {
		t.Fatalf("Failed to create temp dir: %v", err)
	}

	fn(dir)

	if err := os.RemoveAll(dir); err != nil {
		t.Fatalf("Failed to remove test directory at `%s`: %v", dir, err)
	}
}

func TestLockFile(t *testing.T) {
	withTempDir(t, func(dir string) {
		xData := mustCreate(t, filepath.Join(dir, "x"), 0)
		yData := mustCreate(t, filepath.Join(dir, "y"), 1024)
		zData := mustCreate(t, filepath.Join(dir, "z"), 1024*1024)

		// Do not lock this file:
		mustCreate(t, filepath.Join(dir, "meta.yml"), 1024)

		subDir := filepath.Join(dir, "sub")
		if err := os.Mkdir(subDir, 0744); err != nil {
			t.Fatalf("Creating test sub dir failed: %v", err)
		}

		aData := mustCreate(t, filepath.Join(subDir, "a"), 2*1024*1024)

		// Should be overwritten.
		mustCreate(t, filepath.Join(dir, "z.locked"), 2)

		excludes := []string{"meta.yml"}
		if err := LockRepo(dir, "karl", "klaus", excludes, nil); err != nil {
			t.Fatalf("Failed to lock directory: %v", err)
		}

		err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
			if path == dir || strings.HasSuffix(path, "meta.yml") {
				return nil
			}

			if !strings.HasSuffix(path, LockPathSuffix) && path != dir {
				t.Fatalf("%s has not been locked", path)
			}

			return nil
		})

		if err != nil {
			t.Fatalf("walk failed: %v", err)
		}

		// Try with a wrong password:
		if err := UnlockRepo(dir, "karl", "klausi", excludes, nil); err == nil {
			t.Fatalf("unlock worked without correct password")
		}

		// Try with a wrong user:
		if err := UnlockRepo(dir, "karol", "klaus", excludes, nil); err == nil {
			t.Fatalf("unlock worked without correct user")
		}

		if err := UnlockRepo(dir, "karl", "klaus", excludes, nil); err != nil {
			t.Fatalf("unlock failed: %v", err)
		}

		err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
			if strings.HasSuffix(path, LockPathSuffix) && path != dir {
				t.Fatalf("%s is still locked", path)
			}

			cmp := func(expected []byte) {
				data, err := ioutil.ReadFile(path)
				if err != nil {
					t.Fatalf("Failed to read file %s: %v", path, err)
				}

				if !bytes.Equal(expected, data) {
					t.Fatalf("Content differs after lock & unlock: %s", path)
				}
			}

			switch filepath.Base(path) {
			case "a":
				cmp(aData)
			case "x":
				cmp(xData)
			case "y":
				cmp(yData)
			case "z":
				cmp(zData)
			}

			return nil
		})

		if err != nil {
			t.Fatalf("walk after unlock failed: %v", err)
		}

	})
}

func TestLockDirectory(t *testing.T) {
	withTempDir(t, func(dir string) {
		mustCreate(t, filepath.Join(dir, "a/b/x"), 1024)
		mustCreate(t, filepath.Join(dir, "a/b/empty_file"), 0)
		mustCreate(t, filepath.Join(dir, "a/x"), 1024)
		mustCreate(t, filepath.Join(dir, "x"), 1024)

		require.Nil(t, os.MkdirAll(filepath.Join(dir, "empty"), 0744))

		key := make([]byte, 32)
		require.Nil(t, lockDirectory(dir, key))
		require.Nil(t, os.RemoveAll(dir))
		require.Nil(t, unlockDirectory(dir+".tgz.locked", key))

		paths := []string{}
		walker := func(path string, child os.FileInfo, err error) error {
			require.Nil(t, err)
			path = path[len(dir):]
			if len(path) > 0 {
				paths = append(paths, path)
			}

			return nil
		}

		require.Nil(t, filepath.Walk(dir, walker))

		sort.Strings(paths)

		// Note that /empty vanished after untarring.
		// For now we do not support tarring empty directories.
		require.Equal(
			t,
			[]string{
				"/a",
				"/a/b",
				"/a/b/empty_file",
				"/a/b/x",
				"/a/x",
				"/x",
			},
			paths,
		)
	})
}
<|endoftext|>


<commit_before>package models

import (
	"encoding/xml"
	"errors"
	"time"

	"github.com/koding/bongo"
)

var ErrNotSet = errors.New("name is not set")

type SitemapFile struct {
	Id int64

	// unique file name
	Name string `sql:"NOT NULL"`

	// file content
	Blob []byte

	// creation date of the file
	CreatedAt time.Time

	// last modification date of the file
	UpdatedAt time.Time
}

func NewSitemapFile() *SitemapFile {
	return &SitemapFile{}
}

func (f SitemapFile) GetId() int64 {
	return f.Id
}

func (f SitemapFile) TableName() string {
	return "sitemap.file"
}

func (f *SitemapFile) BeforeCreate() error {
	if f.Name == "" {
		return ErrNotSet
	}

	return nil
}

func (f *SitemapFile) Create() error {
	return bongo.B.Create(f)
}

func (f *SitemapFile) One(q *bongo.Query) error {
	return bongo.B.One(f, f, q)
}

func (f *SitemapFile) ByName(name string) error {
	if name == "" {
		return ErrNotSet
	}

	selector := map[string]interface{}{
		"name": name,
	}
	q := bongo.NewQS(selector)

	return f.One(q)
}

func (f *SitemapFile) Update() error {
	return bongo.B.Update(f)
}

func (f *SitemapFile) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(f, data, q)
}

func (f *SitemapFile) Fetch() error {
	return bongo.B.Fetch(f)
}

func (f *SitemapFile) UnmarshalBlob() (*ItemSet, error) {
	set := NewItemSet()

	return set, xml.Unmarshal(f.Blob, set)
}

func (f *SitemapFile) Delete() error {
	return bongo.B.Delete(f)
}
<commit_msg>Social: change fetch function to ById for site map model<commit_after>package models

import (
	"encoding/xml"
	"errors"
	"time"

	"github.com/koding/bongo"
)

var ErrNotSet = errors.New("name is not set")

type SitemapFile struct {
	Id int64

	// unique file name
	Name string `sql:"NOT NULL"`

	// file content
	Blob []byte

	// creation date of the file
	CreatedAt time.Time

	// last modification date of the file
	UpdatedAt time.Time
}

func NewSitemapFile() *SitemapFile {
	return &SitemapFile{}
}

func (f SitemapFile) GetId() int64 {
	return f.Id
}

func (f SitemapFile) TableName() string {
	return "sitemap.file"
}

func (f *SitemapFile) BeforeCreate() error {
	if f.Name == "" {
		return ErrNotSet
	}

	return nil
}

func (f *SitemapFile) Create() error {
	return bongo.B.Create(f)
}

func (f *SitemapFile) One(q *bongo.Query) error {
	return bongo.B.One(f, f, q)
}

func (f *SitemapFile) ByName(name string) error {
	if name == "" {
		return ErrNotSet
	}

	selector := map[string]interface{}{
		"name": name,
	}
	q := bongo.NewQS(selector)

	return f.One(q)
}

func (f *SitemapFile) Update() error {
	return bongo.B.Update(f)
}

func (f *SitemapFile) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(f, data, q)
}

func (f *SitemapFile) ById(id int64) error {
	return bongo.B.Fetch(f, id)
}

func (f *SitemapFile) UnmarshalBlob() (*ItemSet, error) {
	set := NewItemSet()

	return set, xml.Unmarshal(f.Blob, set)
}

func (f *SitemapFile) Delete() error {
	return bongo.B.Delete(f)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess Authors.

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 repltracker

import (
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/mysql/fakesqldb"
	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/dbconfigs"
	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"
)

var (
	now         = time.Now()
	mockNowFunc = func() time.Time {
		return now
	}
)

func TestCreateSchema(t *testing.T) {
	db := fakesqldb.New(t)
	defer db.Close()
	tw := newTestWriter(db, mockNowFunc)
	defer tw.Close()
	writes.Reset()

	db.OrderMatters()
	upsert := fmt.Sprintf("INSERT INTO %s.heartbeat (ts, tabletUid, keyspaceShard) VALUES (%d, %d, '%s') ON DUPLICATE KEY UPDATE ts=VALUES(ts), tabletUid=VALUES(tabletUid)",
		"_vt", now.UnixNano(), tw.tabletAlias.Uid, tw.keyspaceShard)
	failInsert := fakesqldb.ExpectedExecuteFetch{
		Query: upsert,
		Error: mysql.NewSQLError(mysql.ERBadDb, "", "bad db error"),
	}
	db.AddExpectedExecuteFetch(failInsert)
	db.AddExpectedQuery(fmt.Sprintf(sqlCreateSidecarDB, "_vt"), nil)
	db.AddExpectedQuery(fmt.Sprintf(sqlCreateHeartbeatTable, "_vt"), nil)
	db.AddExpectedQuery(upsert, nil)

	err := tw.write()
	require.NoError(t, err)
}

func TestWriteHeartbeat(t *testing.T) {
	db := fakesqldb.New(t)
	defer db.Close()

	tw := newTestWriter(db, mockNowFunc)
	upsert := fmt.Sprintf("INSERT INTO %s.heartbeat (ts, tabletUid, keyspaceShard) VALUES (%d, %d, '%s') ON DUPLICATE KEY UPDATE ts=VALUES(ts), tabletUid=VALUES(tabletUid)",
		"_vt", now.UnixNano(), tw.tabletAlias.Uid, tw.keyspaceShard)
	db.AddQuery(upsert, &sqltypes.Result{})

	writes.Reset()
	writeErrors.Reset()

	tw.writeHeartbeat()
	assert.Equal(t, int64(1), writes.Get())
	assert.Equal(t, int64(0), writeErrors.Get())
}

func TestWriteHeartbeatError(t *testing.T) {
	db := fakesqldb.New(t)
	defer db.Close()

	tw := newTestWriter(db, mockNowFunc)

	writes.Reset()
	writeErrors.Reset()

	tw.writeHeartbeat()
	assert.Equal(t, int64(0), writes.Get())
	assert.Equal(t, int64(1), writeErrors.Get())
}

func newTestWriter(db *fakesqldb.DB, nowFunc func() time.Time) *heartbeatWriter {
	config := tabletenv.NewDefaultConfig()
	config.ReplicationTracker.Mode = tabletenv.Heartbeat
	config.ReplicationTracker.HeartbeatIntervalSeconds = 1

	params, _ := db.ConnParams().MysqlParams()
	cp := *params
	dbc := dbconfigs.NewTestDBConfigs(cp, cp, "")

	tw := newHeartbeatWriter(tabletenv.NewEnv(config, "WriterTest"), topodatapb.TabletAlias{Cell: "test", Uid: 1111})
	tw.keyspaceShard = "test:0"
	tw.now = nowFunc
	tw.pool.Open(dbc.AppWithDB(), dbc.DbaWithDB(), dbc.AppDebugWithDB())

	return tw
}
<commit_msg>with_ddl: fix test<commit_after>/*
Copyright 2019 The Vitess Authors.

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 repltracker

import (
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"vitess.io/vitess/go/mysql/fakesqldb"
	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/dbconfigs"
	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"
)

var (
	now         = time.Now()
	mockNowFunc = func() time.Time {
		return now
	}
)

func TestCreateSchema(t *testing.T) {
	db := fakesqldb.New(t)
	defer db.Close()
	tw := newTestWriter(db, mockNowFunc)
	defer tw.Close()
	writes.Reset()

	db.OrderMatters()
	upsert := fmt.Sprintf("INSERT INTO %s.heartbeat (ts, tabletUid, keyspaceShard) VALUES (%d, %d, '%s') ON DUPLICATE KEY UPDATE ts=VALUES(ts), tabletUid=VALUES(tabletUid)",
		"_vt", now.UnixNano(), tw.tabletAlias.Uid, tw.keyspaceShard)
	db.AddExpectedQuery(fmt.Sprintf(sqlCreateSidecarDB, "_vt"), nil)
	db.AddExpectedQuery(fmt.Sprintf(sqlCreateHeartbeatTable, "_vt"), nil)
	db.AddExpectedQuery(upsert, nil)

	err := tw.write()
	require.NoError(t, err)
}

func TestWriteHeartbeat(t *testing.T) {
	db := fakesqldb.New(t)
	defer db.Close()

	tw := newTestWriter(db, mockNowFunc)
	upsert := fmt.Sprintf("INSERT INTO %s.heartbeat (ts, tabletUid, keyspaceShard) VALUES (%d, %d, '%s') ON DUPLICATE KEY UPDATE ts=VALUES(ts), tabletUid=VALUES(tabletUid)",
		"_vt", now.UnixNano(), tw.tabletAlias.Uid, tw.keyspaceShard)
	db.AddQuery(upsert, &sqltypes.Result{})

	writes.Reset()
	writeErrors.Reset()

	tw.writeHeartbeat()
	assert.Equal(t, int64(1), writes.Get())
	assert.Equal(t, int64(0), writeErrors.Get())
}

func TestWriteHeartbeatError(t *testing.T) {
	db := fakesqldb.New(t)
	defer db.Close()

	tw := newTestWriter(db, mockNowFunc)

	writes.Reset()
	writeErrors.Reset()

	tw.writeHeartbeat()
	assert.Equal(t, int64(0), writes.Get())
	assert.Equal(t, int64(1), writeErrors.Get())
}

func newTestWriter(db *fakesqldb.DB, nowFunc func() time.Time) *heartbeatWriter {
	config := tabletenv.NewDefaultConfig()
	config.ReplicationTracker.Mode = tabletenv.Heartbeat
	config.ReplicationTracker.HeartbeatIntervalSeconds = 1

	params, _ := db.ConnParams().MysqlParams()
	cp := *params
	dbc := dbconfigs.NewTestDBConfigs(cp, cp, "")

	tw := newHeartbeatWriter(tabletenv.NewEnv(config, "WriterTest"), topodatapb.TabletAlias{Cell: "test", Uid: 1111})
	tw.keyspaceShard = "test:0"
	tw.now = nowFunc
	tw.pool.Open(dbc.AppWithDB(), dbc.DbaWithDB(), dbc.AppDebugWithDB())

	return tw
}
<|endoftext|>


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

package fs_test

import (
	"fmt"
	"io/ioutil"
	"path"
	"runtime"

	"golang.org/x/net/context"

	. "github.com/jacobsa/ogletest"
)

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Run the supplied function for each name, with parallelism.
func forEachName(names []string, f func(context.Context, string)) {
	panic("TODO")
}

////////////////////////////////////////////////////////////////////////
// Stress testing
////////////////////////////////////////////////////////////////////////

type StressTest struct {
	fsTest
}

func init() { RegisterTestSuite(&StressTest{}) }

func (t *StressTest) CreateAndReadManyFilesInParallel() {
	const numFiles = 1024

	// Ensure that we get parallelism for this test.
	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU()))

	// Choose a bunch of file names.
	var names []string
	for i := 0; i < numFiles; i++ {
		names = append(names, fmt.Sprintf("%d", i))
	}

	// Create a file for each name with concurrent workers.
	forEachName(
		names,
		func(ctx context.Context, n string) {
			err := ioutil.WriteFile(path.Join(t.Dir, n), []byte(n), 0400)
			AssertEq(nil, err)
		})

	// Read each back.
	forEachName(
		names,
		func(ctx context.Context, n string) {
			contents, err := ioutil.ReadFile(path.Join(t.Dir, n))
			AssertEq(nil, err)
			AssertEq(n, string(contents))
		})
}

func (t *StressTest) LinkAndUnlinkFileManyTimesInParallel() {
	AssertFalse(true, "TODO")
}

func (t *StressTest) TruncateFileManyTimesInParallel() {
	AssertFalse(true, "TODO")
}
<commit_msg>forEachName<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fs_test

import (
	"fmt"
	"io/ioutil"
	"path"
	"runtime"
	"sync"

	. "github.com/jacobsa/ogletest"
)

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Run the supplied function for each name, with parallelism.
func forEachName(names []string, f func(string)) {
	const parallelism = 8

	// Fill a channel.
	c := make(chan string, len(names))
	for _, n := range names {
		c <- n
	}
	close(c)

	// Run workers.
	var wg sync.WaitGroup
	for i := 0; i < parallelism; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for n := range c {
				f(n)
			}
		}()
	}

	wg.Wait()
}

////////////////////////////////////////////////////////////////////////
// Stress testing
////////////////////////////////////////////////////////////////////////

type StressTest struct {
	fsTest
}

func init() { RegisterTestSuite(&StressTest{}) }

func (t *StressTest) CreateAndReadManyFilesInParallel() {
	const numFiles = 1024

	// Ensure that we get parallelism for this test.
	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU()))

	// Choose a bunch of file names.
	var names []string
	for i := 0; i < numFiles; i++ {
		names = append(names, fmt.Sprintf("%d", i))
	}

	// Create a file for each name with concurrent workers.
	forEachName(
		names,
		func(n string) {
			err := ioutil.WriteFile(path.Join(t.Dir, n), []byte(n), 0400)
			AssertEq(nil, err)
		})

	// Read each back.
	forEachName(
		names,
		func(n string) {
			contents, err := ioutil.ReadFile(path.Join(t.Dir, n))
			AssertEq(nil, err)
			AssertEq(n, string(contents))
		})
}

func (t *StressTest) LinkAndUnlinkFileManyTimesInParallel() {
	AssertFalse(true, "TODO")
}

func (t *StressTest) TruncateFileManyTimesInParallel() {
	AssertFalse(true, "TODO")
}
<|endoftext|>


<commit_before>// Copyright 2009 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.

// This package partially implements the TLS 1.1 protocol, as specified in RFC 4346.
package tls

import (
	"io"
	"os"
	"net"
	"time"
)

// A Conn represents a secure connection.
type Conn struct {
	net.Conn
	writeChan                 chan<- []byte
	readChan                  <-chan []byte
	requestChan               chan<- interface{}
	readBuf                   []byte
	eof                       bool
	readTimeout, writeTimeout int64
}

func timeout(c chan<- bool, nsecs int64) {
	time.Sleep(nsecs)
	c <- true
}

func (tls *Conn) Read(p []byte) (int, os.Error) {
	if len(tls.readBuf) == 0 {
		if tls.eof {
			return 0, os.EOF
		}

		var timeoutChan chan bool
		if tls.readTimeout > 0 {
			timeoutChan = make(chan bool)
			go timeout(timeoutChan, tls.readTimeout)
		}

		select {
		case b := <-tls.readChan:
			tls.readBuf = b
		case <-timeoutChan:
			return 0, os.EAGAIN
		}

		// TLS distinguishes between orderly closes and truncations. An
		// orderly close is represented by a zero length slice.
		if closed(tls.readChan) {
			return 0, io.ErrUnexpectedEOF
		}
		if len(tls.readBuf) == 0 {
			tls.eof = true
			return 0, os.EOF
		}
	}

	n := copy(p, tls.readBuf)
	tls.readBuf = tls.readBuf[n:]
	return n, nil
}

func (tls *Conn) Write(p []byte) (int, os.Error) {
	if tls.eof || closed(tls.readChan) {
		return 0, os.EOF
	}

	var timeoutChan chan bool
	if tls.writeTimeout > 0 {
		timeoutChan = make(chan bool)
		go timeout(timeoutChan, tls.writeTimeout)
	}

	select {
	case tls.writeChan <- p:
	case <-timeoutChan:
		return 0, os.EAGAIN
	}

	return len(p), nil
}

func (tls *Conn) Close() os.Error {
	close(tls.writeChan)
	close(tls.requestChan)
	tls.eof = true
	return nil
}

func (tls *Conn) SetTimeout(nsec int64) os.Error {
	tls.readTimeout = nsec
	tls.writeTimeout = nsec
	return nil
}

func (tls *Conn) SetReadTimeout(nsec int64) os.Error {
	tls.readTimeout = nsec
	return nil
}

func (tls *Conn) SetWriteTimeout(nsec int64) os.Error {
	tls.writeTimeout = nsec
	return nil
}

func (tls *Conn) GetConnectionState() ConnectionState {
	replyChan := make(chan ConnectionState)
	tls.requestChan <- getConnectionState{replyChan}
	return <-replyChan
}

func (tls *Conn) WaitConnectionState() ConnectionState {
	replyChan := make(chan ConnectionState)
	tls.requestChan <- waitConnectionState{replyChan}
	return <-replyChan
}

type handshaker interface {
	loop(writeChan chan<- interface{}, controlChan chan<- interface{}, msgChan <-chan interface{}, config *Config)
}

// Server establishes a secure connection over the given connection and acts
// as a TLS server.
func startTLSGoroutines(conn net.Conn, h handshaker, config *Config) *Conn {
	tls := new(Conn)
	tls.Conn = conn

	writeChan := make(chan []byte)
	readChan := make(chan []byte)
	requestChan := make(chan interface{})

	tls.writeChan = writeChan
	tls.readChan = readChan
	tls.requestChan = requestChan

	handshakeWriterChan := make(chan interface{})
	processorHandshakeChan := make(chan interface{})
	handshakeProcessorChan := make(chan interface{})
	readerProcessorChan := make(chan *record)

	go new(recordWriter).loop(conn, writeChan, handshakeWriterChan)
	go recordReader(readerProcessorChan, conn)
	go new(recordProcessor).loop(readChan, requestChan, handshakeProcessorChan, readerProcessorChan, processorHandshakeChan)
	go h.loop(handshakeWriterChan, handshakeProcessorChan, processorHandshakeChan, config)

	return tls
}

func Server(conn net.Conn, config *Config) *Conn {
	return startTLSGoroutines(conn, new(serverHandshake), config)
}

func Client(conn net.Conn, config *Config) *Conn {
	return startTLSGoroutines(conn, new(clientHandshake), config)
}

type Listener struct {
	listener net.Listener
	config   *Config
}

func (l Listener) Accept() (c net.Conn, err os.Error) {
	c, err = l.listener.Accept()
	if err != nil {
		return
	}

	c = Server(c, l.config)
	return
}

func (l Listener) Close() os.Error { return l.listener.Close() }

func (l Listener) Addr() net.Addr { return l.listener.Addr() }

// NewListener creates a Listener which accepts connections from an inner
// Listener and wraps each connection with Server.
func NewListener(listener net.Listener, config *Config) (l Listener) {
	l.listener = listener
	l.config = config
	return
}
<commit_msg>crypto/tls: make Listener a pointer.<commit_after>// Copyright 2009 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.

// This package partially implements the TLS 1.1 protocol, as specified in RFC 4346.
package tls

import (
	"io"
	"os"
	"net"
	"time"
)

// A Conn represents a secure connection.
type Conn struct {
	net.Conn
	writeChan                 chan<- []byte
	readChan                  <-chan []byte
	requestChan               chan<- interface{}
	readBuf                   []byte
	eof                       bool
	readTimeout, writeTimeout int64
}

func timeout(c chan<- bool, nsecs int64) {
	time.Sleep(nsecs)
	c <- true
}

func (tls *Conn) Read(p []byte) (int, os.Error) {
	if len(tls.readBuf) == 0 {
		if tls.eof {
			return 0, os.EOF
		}

		var timeoutChan chan bool
		if tls.readTimeout > 0 {
			timeoutChan = make(chan bool)
			go timeout(timeoutChan, tls.readTimeout)
		}

		select {
		case b := <-tls.readChan:
			tls.readBuf = b
		case <-timeoutChan:
			return 0, os.EAGAIN
		}

		// TLS distinguishes between orderly closes and truncations. An
		// orderly close is represented by a zero length slice.
		if closed(tls.readChan) {
			return 0, io.ErrUnexpectedEOF
		}
		if len(tls.readBuf) == 0 {
			tls.eof = true
			return 0, os.EOF
		}
	}

	n := copy(p, tls.readBuf)
	tls.readBuf = tls.readBuf[n:]
	return n, nil
}

func (tls *Conn) Write(p []byte) (int, os.Error) {
	if tls.eof || closed(tls.readChan) {
		return 0, os.EOF
	}

	var timeoutChan chan bool
	if tls.writeTimeout > 0 {
		timeoutChan = make(chan bool)
		go timeout(timeoutChan, tls.writeTimeout)
	}

	select {
	case tls.writeChan <- p:
	case <-timeoutChan:
		return 0, os.EAGAIN
	}

	return len(p), nil
}

func (tls *Conn) Close() os.Error {
	close(tls.writeChan)
	close(tls.requestChan)
	tls.eof = true
	return nil
}

func (tls *Conn) SetTimeout(nsec int64) os.Error {
	tls.readTimeout = nsec
	tls.writeTimeout = nsec
	return nil
}

func (tls *Conn) SetReadTimeout(nsec int64) os.Error {
	tls.readTimeout = nsec
	return nil
}

func (tls *Conn) SetWriteTimeout(nsec int64) os.Error {
	tls.writeTimeout = nsec
	return nil
}

func (tls *Conn) GetConnectionState() ConnectionState {
	replyChan := make(chan ConnectionState)
	tls.requestChan <- getConnectionState{replyChan}
	return <-replyChan
}

func (tls *Conn) WaitConnectionState() ConnectionState {
	replyChan := make(chan ConnectionState)
	tls.requestChan <- waitConnectionState{replyChan}
	return <-replyChan
}

type handshaker interface {
	loop(writeChan chan<- interface{}, controlChan chan<- interface{}, msgChan <-chan interface{}, config *Config)
}

// Server establishes a secure connection over the given connection and acts
// as a TLS server.
func startTLSGoroutines(conn net.Conn, h handshaker, config *Config) *Conn {
	tls := new(Conn)
	tls.Conn = conn

	writeChan := make(chan []byte)
	readChan := make(chan []byte)
	requestChan := make(chan interface{})

	tls.writeChan = writeChan
	tls.readChan = readChan
	tls.requestChan = requestChan

	handshakeWriterChan := make(chan interface{})
	processorHandshakeChan := make(chan interface{})
	handshakeProcessorChan := make(chan interface{})
	readerProcessorChan := make(chan *record)

	go new(recordWriter).loop(conn, writeChan, handshakeWriterChan)
	go recordReader(readerProcessorChan, conn)
	go new(recordProcessor).loop(readChan, requestChan, handshakeProcessorChan, readerProcessorChan, processorHandshakeChan)
	go h.loop(handshakeWriterChan, handshakeProcessorChan, processorHandshakeChan, config)

	return tls
}

func Server(conn net.Conn, config *Config) *Conn {
	return startTLSGoroutines(conn, new(serverHandshake), config)
}

func Client(conn net.Conn, config *Config) *Conn {
	return startTLSGoroutines(conn, new(clientHandshake), config)
}

type Listener struct {
	listener net.Listener
	config   *Config
}

func (l *Listener) Accept() (c net.Conn, err os.Error) {
	c, err = l.listener.Accept()
	if err != nil {
		return
	}

	c = Server(c, l.config)
	return
}

func (l *Listener) Close() os.Error { return l.listener.Close() }

func (l *Listener) Addr() net.Addr { return l.listener.Addr() }

// NewListener creates a Listener which accepts connections from an inner
// Listener and wraps each connection with Server.
func NewListener(listener net.Listener, config *Config) (l *Listener) {
	l = new(Listener)
	l.listener = listener
	l.config = config
	return
}
<|endoftext|>


<commit_before>package fuse

import (
	"fmt"
	"os"
	"sort"
	"strings"
	"syscall"
)

var openFlagNames map[int]string
var initFlagNames map[int]string
var fuseOpenFlagNames map[int]string
var writeFlagNames map[int]string
var readFlagNames map[int]string
var releaseFlagNames map[int]string
var accessFlagName map[int]string

func init() {
	releaseFlagNames = map[int]string{
		RELEASE_FLUSH: "FLUSH",
	}
	openFlagNames = map[int]string{
		os.O_WRONLY:   "WRONLY",
		os.O_RDWR:     "RDWR",
		os.O_APPEND:   "APPEND",
		os.O_ASYNC:    "ASYNC",
		os.O_CREATE:   "CREAT",
		os.O_EXCL:     "EXCL",
		os.O_NOCTTY:   "NOCTTY",
		os.O_NONBLOCK: "NONBLOCK",
		os.O_SYNC:     "SYNC",
		os.O_TRUNC:    "TRUNC",

		syscall.O_CLOEXEC:   "CLOEXEC",
		syscall.O_DIRECT:    "DIRECT",
		syscall.O_DIRECTORY: "DIRECTORY",
		syscall.O_LARGEFILE: "LARGEFILE",
		syscall.O_NOATIME:   "NOATIME",
	}
	initFlagNames = map[int]string{
		CAP_ASYNC_READ:     "ASYNC_READ",
		CAP_POSIX_LOCKS:    "POSIX_LOCKS",
		CAP_FILE_OPS:       "FILE_OPS",
		CAP_ATOMIC_O_TRUNC: "ATOMIC_O_TRUNC",
		CAP_EXPORT_SUPPORT: "EXPORT_SUPPORT",
		CAP_BIG_WRITES:     "BIG_WRITES",
		CAP_DONT_MASK:      "DONT_MASK",
		CAP_SPLICE_WRITE:   "SPLICE_WRITE",
		CAP_SPLICE_MOVE:    "SPLICE_MOVE",
		CAP_SPLICE_READ:    "SPLICE_READ",
	}
	fuseOpenFlagNames = map[int]string{
		FOPEN_DIRECT_IO:   "DIRECT",
		FOPEN_KEEP_CACHE:  "CACHE",
		FOPEN_NONSEEKABLE: "NONSEEK",
	}
	writeFlagNames = map[int]string{
		WRITE_CACHE:     "CACHE",
		WRITE_LOCKOWNER: "LOCKOWNER",
	}
	readFlagNames = map[int]string{
		READ_LOCKOWNER: "LOCKOWNER",
	}
	accessFlagName = map[int]string{
		X_OK: "x",
		W_OK: "w",
		R_OK: "r",
	}
}

func flagString(names map[int]string, fl int, def string) string {
	s := []string{}
	for k, v := range names {
		if fl&k != 0 {
			s = append(s, v)
			fl ^= k
		}
	}
	if len(s) == 0 && def != "" {
		s = []string{def}
	}
	if fl != 0 {
		s = append(s, fmt.Sprintf("0x%x", fl))
	}

	return strings.Join(s, ",")
}

func (me *OpenIn) String() string {
	return fmt.Sprintf("{%s}", flagString(openFlagNames, int(me.Flags), "O_RDONLY"))
}

type OsFileInfo os.FileInfo

func (me OsFileInfo) String() string {
	return fmt.Sprintf(
		"{%s M0%o S=%d L=%d "+
			"%d:%d "+
			"%d*%d %d:%d "+
			"C %d.%09d "+
			"M %d.%09d "+
			"A %d.%09d}",
		me.Name,
		me.Mode, me.Size, me.Nlink,
		me.Uid, me.Gid,
		me.Blocks, me.Blksize,
		me.Rdev, me.Ino,
		me.Ctime_ns/1e9,
		me.Ctime_ns%1e9,
		me.Mtime_ns/1e9,
		me.Mtime_ns%1e9,
		me.Atime_ns/1e9,
		me.Atime_ns%1e9)
}

type OsFileInfos []*os.FileInfo

func (me OsFileInfos) String() string {
	out := []string{}
	for _, info := range me {
		out = append(out, OsFileInfo(*info).String())
	}
	sort.Strings(out)
	return fmt.Sprintf("[%v]", out)
}

func (me *SetAttrIn) String() string {
	s := []string{}
	if me.Valid&FATTR_MODE != 0 {
		s = append(s, fmt.Sprintf("mode 0%o", me.Mode))
	}
	if me.Valid&FATTR_UID != 0 {
		s = append(s, fmt.Sprintf("uid %d", me.Uid))
	}
	if me.Valid&FATTR_GID != 0 {
		s = append(s, fmt.Sprintf("uid %d", me.Gid))
	}
	if me.Valid&FATTR_SIZE != 0 {
		s = append(s, fmt.Sprintf("size %d", me.Size))
	}
	if me.Valid&FATTR_ATIME != 0 {
		s = append(s, fmt.Sprintf("atime %d %d", me.Atime, me.Atimensec))
	}
	if me.Valid&FATTR_MTIME != 0 {
		s = append(s, fmt.Sprintf("mtime %d %d", me.Mtime, me.Mtimensec))
	}
	if me.Valid&FATTR_MTIME != 0 {
		s = append(s, fmt.Sprintf("fh %d", me.Fh))
	}
	// TODO - FATTR_ATIME_NOW = (1 << 7), FATTR_MTIME_NOW = (1 << 8), FATTR_LOCKOWNER = (1 << 9)
	return fmt.Sprintf("{%s}", strings.Join(s, ", "))
}

func (me *Attr) String() string {
	return fmt.Sprintf(
		"{M0%o S=%d L=%d "+
			"%d:%d "+
			"%d*%d %d:%d "+
			"A %d.%09d "+
			"M %d.%09d "+
			"C %d.%09d}",
		me.Mode, me.Size, me.Nlink,
		me.Uid, me.Gid,
		me.Blocks, me.Blksize,
		me.Rdev, me.Ino, me.Atime, me.Atimensec, me.Mtime, me.Mtimensec,
		me.Ctime, me.Ctimensec)
}

func (me *AttrOut) String() string {
	return fmt.Sprintf(
		"{A%d.%09d %v}",
		me.AttrValid, me.AttrValidNsec, &me.Attr)
}

func (me *CreateIn) String() string {
	return fmt.Sprintf(
		"{0%o [%s] (0%o)}", me.Mode,
		flagString(openFlagNames, int(me.Flags), "O_RDONLY"), me.Umask)
}

func (me *EntryOut) String() string {
	return fmt.Sprintf("{%d E%d.%09d A%d.%09d %v}",
		me.NodeId, me.EntryValid, me.EntryValidNsec,
		me.AttrValid, me.AttrValidNsec, &me.Attr)
}

func (me *CreateOut) String() string {
	return fmt.Sprintf("{%v %v}", &me.EntryOut, &me.OpenOut)
}

func (me *OpenOut) String() string {
	return fmt.Sprintf("{Fh %d %s}", me.Fh,
		flagString(fuseOpenFlagNames, int(me.OpenFlags), ""))
}

func (me *GetAttrIn) String() string {
	return fmt.Sprintf("{Fh %d}", me.Fh)
}

func (me *InitIn) String() string {
	return fmt.Sprintf("{%d.%d Ra 0x%x %s}",
		me.Major, me.Minor, me.MaxReadAhead,
		flagString(initFlagNames, int(me.Flags), ""))
}
func (me *InitOut) String() string {
	return fmt.Sprintf("{%d.%d Ra 0x%x %s %d/%d Wr 0x%x}",
		me.Major, me.Minor, me.MaxReadAhead,
		flagString(initFlagNames, int(me.Flags), ""),
		me.CongestionThreshold, me.MaxBackground, me.MaxWrite)
}

func (me *ReadIn) String() string {
	return fmt.Sprintf("{Fh %d off %d sz %d %s L %d %s}",
		me.Fh, me.Offset, me.Size,
		flagString(readFlagNames, int(me.ReadFlags), ""),
		me.LockOwner,
		flagString(openFlagNames, int(me.Flags), "RDONLY"))
}

func (me *MkdirIn) String() string {
	return fmt.Sprintf("{0%o (0%o)}", me.Mode, me.Umask)
}

func (me *MknodIn) String() string {
	return fmt.Sprintf("{0%o (0%o), %d}", me.Mode, me.Umask, me.Rdev)
}

func (me *ReleaseIn) String() string {
	return fmt.Sprintf("{Fh %d %s %s L%d}",
		me.Fh, flagString(openFlagNames, int(me.Flags), ""),
		flagString(releaseFlagNames, int(me.ReleaseFlags), ""),
		me.LockOwner)
}

func (me *FlushIn) String() string {
	return fmt.Sprintf("{Fh %d}", me.Fh)
}

func (me *AccessIn) String() string {
	return fmt.Sprintf("{%s}", flagString(accessFlagName, int(me.Mask), ""))
}

func (me *Kstatfs) String() string {
	return fmt.Sprintf(
		"{b%d f%d fs%d ff%d bs%d nl%d frs%d}",
		me.Blocks, me.Bfree, me.Bavail, me.Files, me.Ffree,
		me.Bsize, me.NameLen, me.Frsize)
}

func (me *WithFlags) String() string {
	return fmt.Sprintf("File %s (%s) %s %s",
		me.File, me.Description, flagString(openFlagNames, int(me.OpenFlags), "O_RDONLY"),
		flagString(fuseOpenFlagNames, int(me.FuseFlags), ""))
}
<commit_msg>Print setattr nanosecs prettily.<commit_after>package fuse

import (
	"fmt"
	"os"
	"sort"
	"strings"
	"syscall"
)

var openFlagNames map[int]string
var initFlagNames map[int]string
var fuseOpenFlagNames map[int]string
var writeFlagNames map[int]string
var readFlagNames map[int]string
var releaseFlagNames map[int]string
var accessFlagName map[int]string

func init() {
	releaseFlagNames = map[int]string{
		RELEASE_FLUSH: "FLUSH",
	}
	openFlagNames = map[int]string{
		os.O_WRONLY:   "WRONLY",
		os.O_RDWR:     "RDWR",
		os.O_APPEND:   "APPEND",
		os.O_ASYNC:    "ASYNC",
		os.O_CREATE:   "CREAT",
		os.O_EXCL:     "EXCL",
		os.O_NOCTTY:   "NOCTTY",
		os.O_NONBLOCK: "NONBLOCK",
		os.O_SYNC:     "SYNC",
		os.O_TRUNC:    "TRUNC",

		syscall.O_CLOEXEC:   "CLOEXEC",
		syscall.O_DIRECT:    "DIRECT",
		syscall.O_DIRECTORY: "DIRECTORY",
		syscall.O_LARGEFILE: "LARGEFILE",
		syscall.O_NOATIME:   "NOATIME",
	}
	initFlagNames = map[int]string{
		CAP_ASYNC_READ:     "ASYNC_READ",
		CAP_POSIX_LOCKS:    "POSIX_LOCKS",
		CAP_FILE_OPS:       "FILE_OPS",
		CAP_ATOMIC_O_TRUNC: "ATOMIC_O_TRUNC",
		CAP_EXPORT_SUPPORT: "EXPORT_SUPPORT",
		CAP_BIG_WRITES:     "BIG_WRITES",
		CAP_DONT_MASK:      "DONT_MASK",
		CAP_SPLICE_WRITE:   "SPLICE_WRITE",
		CAP_SPLICE_MOVE:    "SPLICE_MOVE",
		CAP_SPLICE_READ:    "SPLICE_READ",
	}
	fuseOpenFlagNames = map[int]string{
		FOPEN_DIRECT_IO:   "DIRECT",
		FOPEN_KEEP_CACHE:  "CACHE",
		FOPEN_NONSEEKABLE: "NONSEEK",
	}
	writeFlagNames = map[int]string{
		WRITE_CACHE:     "CACHE",
		WRITE_LOCKOWNER: "LOCKOWNER",
	}
	readFlagNames = map[int]string{
		READ_LOCKOWNER: "LOCKOWNER",
	}
	accessFlagName = map[int]string{
		X_OK: "x",
		W_OK: "w",
		R_OK: "r",
	}
}

func flagString(names map[int]string, fl int, def string) string {
	s := []string{}
	for k, v := range names {
		if fl&k != 0 {
			s = append(s, v)
			fl ^= k
		}
	}
	if len(s) == 0 && def != "" {
		s = []string{def}
	}
	if fl != 0 {
		s = append(s, fmt.Sprintf("0x%x", fl))
	}

	return strings.Join(s, ",")
}

func (me *OpenIn) String() string {
	return fmt.Sprintf("{%s}", flagString(openFlagNames, int(me.Flags), "O_RDONLY"))
}

type OsFileInfo os.FileInfo

func (me OsFileInfo) String() string {
	return fmt.Sprintf(
		"{%s M0%o S=%d L=%d "+
			"%d:%d "+
			"%d*%d %d:%d "+
			"C %d.%09d "+
			"M %d.%09d "+
			"A %d.%09d}",
		me.Name,
		me.Mode, me.Size, me.Nlink,
		me.Uid, me.Gid,
		me.Blocks, me.Blksize,
		me.Rdev, me.Ino,
		me.Ctime_ns/1e9,
		me.Ctime_ns%1e9,
		me.Mtime_ns/1e9,
		me.Mtime_ns%1e9,
		me.Atime_ns/1e9,
		me.Atime_ns%1e9)
}

type OsFileInfos []*os.FileInfo

func (me OsFileInfos) String() string {
	out := []string{}
	for _, info := range me {
		out = append(out, OsFileInfo(*info).String())
	}
	sort.Strings(out)
	return fmt.Sprintf("[%v]", out)
}

func (me *SetAttrIn) String() string {
	s := []string{}
	if me.Valid&FATTR_MODE != 0 {
		s = append(s, fmt.Sprintf("mode 0%o", me.Mode))
	}
	if me.Valid&FATTR_UID != 0 {
		s = append(s, fmt.Sprintf("uid %d", me.Uid))
	}
	if me.Valid&FATTR_GID != 0 {
		s = append(s, fmt.Sprintf("uid %d", me.Gid))
	}
	if me.Valid&FATTR_SIZE != 0 {
		s = append(s, fmt.Sprintf("size %d", me.Size))
	}
	if me.Valid&FATTR_ATIME != 0 {
		s = append(s, fmt.Sprintf("atime %d.%09d", me.Atime, me.Atimensec))
	}
	if me.Valid&FATTR_MTIME != 0 {
		s = append(s, fmt.Sprintf("mtime %d.%09d", me.Mtime, me.Mtimensec))
	}
	if me.Valid&FATTR_MTIME != 0 {
		s = append(s, fmt.Sprintf("fh %d", me.Fh))
	}
	// TODO - FATTR_ATIME_NOW = (1 << 7), FATTR_MTIME_NOW = (1 << 8), FATTR_LOCKOWNER = (1 << 9)
	return fmt.Sprintf("{%s}", strings.Join(s, ", "))
}

func (me *Attr) String() string {
	return fmt.Sprintf(
		"{M0%o S=%d L=%d "+
			"%d:%d "+
			"%d*%d %d:%d "+
			"A %d.%09d "+
			"M %d.%09d "+
			"C %d.%09d}",
		me.Mode, me.Size, me.Nlink,
		me.Uid, me.Gid,
		me.Blocks, me.Blksize,
		me.Rdev, me.Ino, me.Atime, me.Atimensec, me.Mtime, me.Mtimensec,
		me.Ctime, me.Ctimensec)
}

func (me *AttrOut) String() string {
	return fmt.Sprintf(
		"{A%d.%09d %v}",
		me.AttrValid, me.AttrValidNsec, &me.Attr)
}

func (me *CreateIn) String() string {
	return fmt.Sprintf(
		"{0%o [%s] (0%o)}", me.Mode,
		flagString(openFlagNames, int(me.Flags), "O_RDONLY"), me.Umask)
}

func (me *EntryOut) String() string {
	return fmt.Sprintf("{%d E%d.%09d A%d.%09d %v}",
		me.NodeId, me.EntryValid, me.EntryValidNsec,
		me.AttrValid, me.AttrValidNsec, &me.Attr)
}

func (me *CreateOut) String() string {
	return fmt.Sprintf("{%v %v}", &me.EntryOut, &me.OpenOut)
}

func (me *OpenOut) String() string {
	return fmt.Sprintf("{Fh %d %s}", me.Fh,
		flagString(fuseOpenFlagNames, int(me.OpenFlags), ""))
}

func (me *GetAttrIn) String() string {
	return fmt.Sprintf("{Fh %d}", me.Fh)
}

func (me *InitIn) String() string {
	return fmt.Sprintf("{%d.%d Ra 0x%x %s}",
		me.Major, me.Minor, me.MaxReadAhead,
		flagString(initFlagNames, int(me.Flags), ""))
}
func (me *InitOut) String() string {
	return fmt.Sprintf("{%d.%d Ra 0x%x %s %d/%d Wr 0x%x}",
		me.Major, me.Minor, me.MaxReadAhead,
		flagString(initFlagNames, int(me.Flags), ""),
		me.CongestionThreshold, me.MaxBackground, me.MaxWrite)
}

func (me *ReadIn) String() string {
	return fmt.Sprintf("{Fh %d off %d sz %d %s L %d %s}",
		me.Fh, me.Offset, me.Size,
		flagString(readFlagNames, int(me.ReadFlags), ""),
		me.LockOwner,
		flagString(openFlagNames, int(me.Flags), "RDONLY"))
}

func (me *MkdirIn) String() string {
	return fmt.Sprintf("{0%o (0%o)}", me.Mode, me.Umask)
}

func (me *MknodIn) String() string {
	return fmt.Sprintf("{0%o (0%o), %d}", me.Mode, me.Umask, me.Rdev)
}

func (me *ReleaseIn) String() string {
	return fmt.Sprintf("{Fh %d %s %s L%d}",
		me.Fh, flagString(openFlagNames, int(me.Flags), ""),
		flagString(releaseFlagNames, int(me.ReleaseFlags), ""),
		me.LockOwner)
}

func (me *FlushIn) String() string {
	return fmt.Sprintf("{Fh %d}", me.Fh)
}

func (me *AccessIn) String() string {
	return fmt.Sprintf("{%s}", flagString(accessFlagName, int(me.Mask), ""))
}

func (me *Kstatfs) String() string {
	return fmt.Sprintf(
		"{b%d f%d fs%d ff%d bs%d nl%d frs%d}",
		me.Blocks, me.Bfree, me.Bavail, me.Files, me.Ffree,
		me.Bsize, me.NameLen, me.Frsize)
}

func (me *WithFlags) String() string {
	return fmt.Sprintf("File %s (%s) %s %s",
		me.File, me.Description, flagString(openFlagNames, int(me.OpenFlags), "O_RDONLY"),
		flagString(fuseOpenFlagNames, int(me.FuseFlags), ""))
}
<|endoftext|>


<commit_before>package http

import (
	"encoding/json"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/GeertJohan/go.rice"
	"github.com/filebrowser/filebrowser/v2/auth"
	"github.com/filebrowser/filebrowser/v2/storage"
	"github.com/filebrowser/filebrowser/v2/version"
)

func handleWithStaticData(w http.ResponseWriter, r *http.Request, d *data, box *rice.Box, file, contentType string) (int, error) {
	w.Header().Set("Content-Type", contentType)

	staticURL := strings.TrimPrefix(d.settings.BaseURL+"/static", "/")

	data := map[string]interface{}{
		"Name":            d.settings.Branding.Name,
		"DisableExternal": d.settings.Branding.DisableExternal,
		"BaseURL":         d.settings.BaseURL,
		"Version":         version.Version,
		"StaticURL":       staticURL,
		"Signup":          d.settings.Signup,
		"NoAuth":          d.settings.AuthMethod == auth.MethodNoAuth,
		"CSS":             false,
		"ReCaptcha":       false,
	}

	if d.settings.Branding.Files != "" {
		path := filepath.Join(d.settings.Branding.Files, "custom.css")
		_, err := os.Stat(path)

		if err != nil && !os.IsNotExist(err) {
			log.Printf("couldn't load custom styles: %v", err)
		}

		if err == nil {
			data["CSS"] = true
		}
	}

	if d.settings.AuthMethod == auth.MethodJSONAuth {
		raw, err := d.store.Auth.Get(d.settings.AuthMethod)
		if err != nil {
			return http.StatusInternalServerError, err
		}

		auther := raw.(*auth.JSONAuth)

		if auther.ReCaptcha != nil {
			data["ReCaptcha"] = auther.ReCaptcha.Key != "" && auther.ReCaptcha.Secret != ""
			data["ReCaptchaHost"] = auther.ReCaptcha.Host
			data["ReCaptchaKey"] = auther.ReCaptcha.Key
		}
	}

	b, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return http.StatusInternalServerError, err
	}

	data["Json"] = string(b)

	index := template.Must(template.New("index").Delims("[{[", "]}]").Parse(box.MustString(file)))
	err = index.Execute(w, data)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	return 0, nil
}

func getStaticHandlers(storage *storage.Storage) (http.Handler, http.Handler) {
	box := rice.MustFindBox("../frontend/dist")
	handler := http.FileServer(box.HTTPBox())

	index := handle(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
		if r.Method != http.MethodGet {
			return http.StatusNotFound, nil
		}

		w.Header().Set("x-frame-options", "SAMEORIGIN")
		w.Header().Set("x-xss-protection", "1; mode=block")

		return handleWithStaticData(w, r, d, box, "index.html", "text/html; charset=utf-8")
	}, "", storage)

	static := handle(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
		if r.Method != http.MethodGet {
			return http.StatusNotFound, nil
		}

		if d.settings.Branding.Files != "" {
			if strings.HasPrefix(r.URL.Path, "img/") {
				path := filepath.Join(d.settings.Branding.Files, r.URL.Path)
				if _, err := os.Stat(path); err == nil {
					http.ServeFile(w, r, path)
					return 0, nil
				}
			} else if r.URL.Path == "custom.css" && d.settings.Branding.Files != "" {
				http.ServeFile(w, r, filepath.Join(d.settings.Branding.Files, "custom.css"))
				return 0, nil
			}
		}

		if !strings.HasSuffix(r.URL.Path, ".js") {
			handler.ServeHTTP(w, r)
			return 0, nil
		}

		return handleWithStaticData(w, r, d, box, r.URL.Path, "application/javascript; charset=utf-8")
	}, "/static/", storage)

	return index, static
}
<commit_msg>fix: allow embedding into iframes (close #550)<commit_after>package http

import (
	"encoding/json"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/GeertJohan/go.rice"
	"github.com/filebrowser/filebrowser/v2/auth"
	"github.com/filebrowser/filebrowser/v2/storage"
	"github.com/filebrowser/filebrowser/v2/version"
)

func handleWithStaticData(w http.ResponseWriter, r *http.Request, d *data, box *rice.Box, file, contentType string) (int, error) {
	w.Header().Set("Content-Type", contentType)

	staticURL := strings.TrimPrefix(d.settings.BaseURL+"/static", "/")

	data := map[string]interface{}{
		"Name":            d.settings.Branding.Name,
		"DisableExternal": d.settings.Branding.DisableExternal,
		"BaseURL":         d.settings.BaseURL,
		"Version":         version.Version,
		"StaticURL":       staticURL,
		"Signup":          d.settings.Signup,
		"NoAuth":          d.settings.AuthMethod == auth.MethodNoAuth,
		"CSS":             false,
		"ReCaptcha":       false,
	}

	if d.settings.Branding.Files != "" {
		path := filepath.Join(d.settings.Branding.Files, "custom.css")
		_, err := os.Stat(path)

		if err != nil && !os.IsNotExist(err) {
			log.Printf("couldn't load custom styles: %v", err)
		}

		if err == nil {
			data["CSS"] = true
		}
	}

	if d.settings.AuthMethod == auth.MethodJSONAuth {
		raw, err := d.store.Auth.Get(d.settings.AuthMethod)
		if err != nil {
			return http.StatusInternalServerError, err
		}

		auther := raw.(*auth.JSONAuth)

		if auther.ReCaptcha != nil {
			data["ReCaptcha"] = auther.ReCaptcha.Key != "" && auther.ReCaptcha.Secret != ""
			data["ReCaptchaHost"] = auther.ReCaptcha.Host
			data["ReCaptchaKey"] = auther.ReCaptcha.Key
		}
	}

	b, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return http.StatusInternalServerError, err
	}

	data["Json"] = string(b)

	index := template.Must(template.New("index").Delims("[{[", "]}]").Parse(box.MustString(file)))
	err = index.Execute(w, data)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	return 0, nil
}

func getStaticHandlers(storage *storage.Storage) (http.Handler, http.Handler) {
	box := rice.MustFindBox("../frontend/dist")
	handler := http.FileServer(box.HTTPBox())

	index := handle(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
		if r.Method != http.MethodGet {
			return http.StatusNotFound, nil
		}

		w.Header().Set("x-xss-protection", "1; mode=block")
		return handleWithStaticData(w, r, d, box, "index.html", "text/html; charset=utf-8")
	}, "", storage)

	static := handle(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
		if r.Method != http.MethodGet {
			return http.StatusNotFound, nil
		}

		if d.settings.Branding.Files != "" {
			if strings.HasPrefix(r.URL.Path, "img/") {
				path := filepath.Join(d.settings.Branding.Files, r.URL.Path)
				if _, err := os.Stat(path); err == nil {
					http.ServeFile(w, r, path)
					return 0, nil
				}
			} else if r.URL.Path == "custom.css" && d.settings.Branding.Files != "" {
				http.ServeFile(w, r, filepath.Join(d.settings.Branding.Files, "custom.css"))
				return 0, nil
			}
		}

		if !strings.HasSuffix(r.URL.Path, ".js") {
			handler.ServeHTTP(w, r)
			return 0, nil
		}

		return handleWithStaticData(w, r, d, box, r.URL.Path, "application/javascript; charset=utf-8")
	}, "/static/", storage)

	return index, static
}
<|endoftext|>


<commit_before>package gcm

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"

	"github.com/golang/glog"
)

type Config struct {
	Port   int
	APIKey string
}

type Proxy struct {
	cfg *Config
}

type Payload struct {
	RegistrationIds []string `json:"registration_ids"`
	Data            *Data    `json:"data"`
}

type Data struct {
	Message string `json:"message"`
}

var Endpoint string = "https://android.googleapis.com/gcm/send"
var proxy *Proxy

func NewProxy(config *Config) (*Proxy, error) {
	if config.Port == 0 {
		return nil, errors.New("Please Set Port")
	}
	if config.APIKey == "" {
		return nil, errors.New("Please Set APIKey")
	}

	proxy = &Proxy{
		cfg: config,
	}

	return proxy, nil
}

func (p *Proxy) Run() {
	fmt.Printf("gcm-proxy start 0.0.0.0:%d \n", p.cfg.Port)
	http.HandleFunc("/", Reciver)
	http.ListenAndServe(":"+strconv.Itoa(p.cfg.Port), nil)
}

func Reciver(w http.ResponseWriter, req *http.Request) {
	flag.Parse()

	if req.Method == "GET" {
		http.Error(w, "Method Not Allowd", http.StatusMethodNotAllowed)
		return
	}

	if req.Body == nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}

	defer req.Body.Close()
	err := req.ParseForm()
	if err != nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
	}

	// TODO
	// when header json
	if req.Form.Get("token") == "" {
		glog.Error("Parameter [token] is empty")
		http.Error(w, "Lack Parameter", http.StatusBadRequest)
		return
	}

	if req.Form.Get("alert") == "" {
		glog.Error("Parameter [alert] is empty")
		http.Error(w, "Lack Parameter", http.StatusBadRequest)
		return
	}

	tokens := strings.Split(req.Form.Get("token"), ",")
	alert := req.Form.Get("alert")

	data := &Data{Message: alert}
	payload := &Payload{
		RegistrationIds: tokens,
		Data:            data,
	}

	send(payload)

	w.WriteHeader(http.StatusOK)
}

func send(payload *Payload) {
	flag.Parse()

	p, err := json.Marshal(payload)
	body := strings.NewReader(string(p))
	if err != nil {
		glog.Errorf("Create New Reader Error: %s", err.Error())
	}

	go func() {
		req, err := http.NewRequest("POST", Endpoint, body)
		if err != nil {
			glog.Errorf("Create NewRequest Error: %s", err.Error())
		}

		apiKey := getAPIKey()

		req.Header.Set("Authorization", "key="+apiKey)
		req.Header.Set("Content-Type", "application/json")

		client := &http.Client{}

		resp, err := client.Do(req)

		if err != nil {
			glog.Errorf("Post GCM Error: %s", err.Error())
		}

		defer resp.Body.Close()
		respBody, err := ioutil.ReadAll(resp.Body)
		// if happend error post retry
		if !strings.Contains(resp.Status, "200") {
			glog.Errorf("Post GCM Error: %s", string(respBody))
		} else {
			glog.Infof("Post GCM Success: %s", string(respBody))
		}
	}()
}

// for testing method
func getAPIKey() string {
	var apiKey string

	if proxy == nil {
		apiKey = "test api key"
	} else {
		apiKey = proxy.cfg.APIKey
	}

	return apiKey
}
<commit_msg>remove debug message<commit_after>package gcm

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"

	"github.com/golang/glog"
)

type Config struct {
	Port   int
	APIKey string
}

type Proxy struct {
	cfg *Config
}

type Payload struct {
	RegistrationIds []string `json:"registration_ids"`
	Data            *Data    `json:"data"`
}

type Data struct {
	Message string `json:"message"`
}

var Endpoint string = "https://android.googleapis.com/gcm/send"
var proxy *Proxy

func NewProxy(config *Config) (*Proxy, error) {
	if config.Port == 0 {
		return nil, errors.New("Please Set Port")
	}
	if config.APIKey == "" {
		return nil, errors.New("Please Set APIKey")
	}

	proxy = &Proxy{
		cfg: config,
	}

	return proxy, nil
}

func (p *Proxy) Run() {
	fmt.Printf("gcm-proxy start 0.0.0.0:%d \n", p.cfg.Port)
	http.HandleFunc("/", Reciver)
	http.ListenAndServe(":"+strconv.Itoa(p.cfg.Port), nil)
}

func Reciver(w http.ResponseWriter, req *http.Request) {
	flag.Parse()

	if req.Method == "GET" {
		http.Error(w, "Method Not Allowd", http.StatusMethodNotAllowed)
		return
	}

	if req.Body == nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}

	defer req.Body.Close()
	err := req.ParseForm()
	if err != nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
	}

	// TODO
	// when header json
	if req.Form.Get("token") == "" {
		glog.Error("Parameter [token] is empty")
		http.Error(w, "Lack Parameter", http.StatusBadRequest)
		return
	}

	if req.Form.Get("alert") == "" {
		glog.Error("Parameter [alert] is empty")
		http.Error(w, "Lack Parameter", http.StatusBadRequest)
		return
	}

	tokens := strings.Split(req.Form.Get("token"), ",")
	alert := req.Form.Get("alert")

	data := &Data{Message: alert}
	payload := &Payload{
		RegistrationIds: tokens,
		Data:            data,
	}

	send(payload)

	w.WriteHeader(http.StatusOK)
}

func send(payload *Payload) {
	flag.Parse()

	p, err := json.Marshal(payload)
	body := strings.NewReader(string(p))
	if err != nil {
		glog.Errorf("Create New Reader Error: %s", err.Error())
	}

	go func() {
		req, err := http.NewRequest("POST", Endpoint, body)
		if err != nil {
			glog.Errorf("Create NewRequest Error: %s", err.Error())
		}

		apiKey := getAPIKey()

		req.Header.Set("Authorization", "key="+apiKey)
		req.Header.Set("Content-Type", "application/json")

		client := &http.Client{}

		resp, err := client.Do(req)

		if err != nil {
			glog.Errorf("Post GCM Error: %s", err.Error())
		}

		defer resp.Body.Close()
		respBody, err := ioutil.ReadAll(resp.Body)

		if !strings.Contains(resp.Status, "200") {
			glog.Errorf("Post GCM Error: %s", string(respBody))
		} else {
			glog.Infof("Post GCM Success: %s", string(respBody))
		}
	}()
}

// for testing method
func getAPIKey() string {
	var apiKey string

	if proxy == nil {
		apiKey = "test api key"
	} else {
		apiKey = proxy.cfg.APIKey
	}

	return apiKey
}
<|endoftext|>