<commit_before>package rpcd

import (
	"encoding/gob"
	"fmt"
	"github.com/Symantec/Dominator/proto/objectserver"
	"io"
	"net/http"
	"sync"
)

var exclusive sync.RWMutex

func getObjectsHandler(w http.ResponseWriter, req *http.Request) {
	if req.Method != "CONNECT" {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusMethodNotAllowed)
		io.WriteString(w, "405 must CONNECT\n")
		return
	}
	conn, bufrw, err := w.(http.Hijacker).Hijack()
	if err != nil {
		fmt.Println("rpc hijacking ", req.RemoteAddr, ": ", err.Error())
		return
	}
	defer conn.Close()
	defer bufrw.Flush()
	io.WriteString(conn, "HTTP/1.0 200 Connected to GetObjects RPC\n\n")
	var request objectserver.GetObjectsRequest
	var response objectserver.GetObjectsResponse
	if request.Exclusive {
		exclusive.Lock()
		defer exclusive.Unlock()
	} else {
		exclusive.RLock()
		defer exclusive.RUnlock()
	}
	decoder := gob.NewDecoder(bufrw)
	encoder := gob.NewEncoder(bufrw)
	err = decoder.Decode(&request)
	if err != nil {
		response.ResponseString = err.Error()
		encoder.Encode(response)
		return
	}
	response.ObjectSizes, err = objectServer.CheckObjects(request.Hashes)
	if err != nil {
		response.ResponseString = err.Error()
		encoder.Encode(response)
		return
	}
	// First a quick check for existence. If any objects missing, fail request.
	for index, hash := range request.Hashes {
		if response.ObjectSizes[index] < 1 {
			response.ResponseString = fmt.Sprintf("unknown object: %x", hash)
			encoder.Encode(response)
			return
		}
	}
	objectsReader, err := objectServer.GetObjects(request.Hashes)
	if err != nil {
		response.ResponseString = err.Error()
		encoder.Encode(response)
		return
	}
	encoder.Encode(response)
	bufrw.Flush()
	for range request.Hashes {
		_, reader, err := objectsReader.NextObject()
		if err != nil {
			fmt.Println(err)
			return
		}
		_, err = io.Copy(conn, reader)
		if err != nil {
			fmt.Printf("Error copying:\t%s\n", err)
			return
		}
	}
}
<commit_msg>Fix file leak in objectserver GetObjects() RPC handler.<commit_after>package rpcd

import (
	"encoding/gob"
	"fmt"
	"github.com/Symantec/Dominator/proto/objectserver"
	"io"
	"net/http"
	"sync"
)

var exclusive sync.RWMutex

func getObjectsHandler(w http.ResponseWriter, req *http.Request) {
	if req.Method != "CONNECT" {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusMethodNotAllowed)
		io.WriteString(w, "405 must CONNECT\n")
		return
	}
	conn, bufrw, err := w.(http.Hijacker).Hijack()
	if err != nil {
		fmt.Println("rpc hijacking ", req.RemoteAddr, ": ", err.Error())
		return
	}
	defer conn.Close()
	defer bufrw.Flush()
	io.WriteString(conn, "HTTP/1.0 200 Connected to GetObjects RPC\n\n")
	var request objectserver.GetObjectsRequest
	var response objectserver.GetObjectsResponse
	if request.Exclusive {
		exclusive.Lock()
		defer exclusive.Unlock()
	} else {
		exclusive.RLock()
		defer exclusive.RUnlock()
	}
	decoder := gob.NewDecoder(bufrw)
	encoder := gob.NewEncoder(bufrw)
	err = decoder.Decode(&request)
	if err != nil {
		response.ResponseString = err.Error()
		encoder.Encode(response)
		return
	}
	response.ObjectSizes, err = objectServer.CheckObjects(request.Hashes)
	if err != nil {
		response.ResponseString = err.Error()
		encoder.Encode(response)
		return
	}
	// First a quick check for existence. If any objects missing, fail request.
	for index, hash := range request.Hashes {
		if response.ObjectSizes[index] < 1 {
			response.ResponseString = fmt.Sprintf("unknown object: %x", hash)
			encoder.Encode(response)
			return
		}
	}
	objectsReader, err := objectServer.GetObjects(request.Hashes)
	if err != nil {
		response.ResponseString = err.Error()
		encoder.Encode(response)
		return
	}
	encoder.Encode(response)
	bufrw.Flush()
	for range request.Hashes {
		_, reader, err := objectsReader.NextObject()
		if err != nil {
			fmt.Println(err)
			return
		}
		_, err = io.Copy(conn, reader)
		reader.Close()
		if err != nil {
			fmt.Printf("Error copying:\t%s\n", err)
			return
		}
	}
}
<|endoftext|>


<commit_before>package fogbugz

import (
	"encoding/xml"
	"errors"
	"fmt"
	"net/http"
	"net/url"
)

type Session struct {
	host  string
	token string
}

type Config interface {
	GetEmail() string
	GetPassword() string
	GetHost() string
}

type errorCodeTag struct {
	ErrorCode int    `xml:"code,attr"`
	ErrorDesc string `xml:",chardata"`
}

type caseTag struct {
	BugNumber  string `xml:"ixBug,attr"`
	Operations string
}

func (session *Session) FileBug(project string, area string, title string, content string) (string, error) {
	values := url.Values{}
	values.Set("cmd", "new")
	values.Set("token", session.token)
	values.Set("sProject", project)
	values.Set("sArea", area)
	values.Set("sTitle", title)
	values.Set("sEvent", content)
	url := &url.URL{"https", "", nil, session.host, "/api.asp", values.Encode(), ""}

	resp, err := http.Get(url.String())
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	type Response struct {
		XMLName xml.Name     `xml:"response"`
		Case    caseTag      `xml:"case"`
		Error   errorCodeTag `xml:"error"`
	}

	var r Response
	dec := xml.NewDecoder(resp.Body)
	err = dec.Decode(&r)
	if err != nil {
		return "", err
	}

	if r.Error.ErrorCode != 0 {
		return "", errors.New(fmt.Sprintf("Fogbugz error %d: %s", r.Error.ErrorCode, r.Error.ErrorDesc))
	}

	return fmt.Sprintf("https://%s/default.asp?%s", session.host, r.Case.BugNumber), nil
}

func fecthAuthToken(config Config) (string, error) {
	values := url.Values{}
	values.Set("cmd", "logon")
	values.Set("email", config.GetEmail())
	values.Set("password", config.GetPassword())
	url := &url.URL{"https", "", nil, config.GetHost(), "/api.asp", values.Encode(), ""}

	resp, err := http.Get(url.String())
	if err != nil {
		return "", err
	}

	defer resp.Body.Close()

	type Response struct {
		XMLName xml.Name     `xml:"response"`
		Token   string       `xml:"token"`
		Error   errorCodeTag `xml:"error"`
	}

	var r Response
	dec := xml.NewDecoder(resp.Body)
	err = dec.Decode(&r)
	if err != nil {
		return "", err
	}

	if r.Error.ErrorCode != 0 {
		return "", errors.New(fmt.Sprintf("Fogbugz error %d: %s", r.Error.ErrorCode, r.Error.ErrorDesc))
	}

	return r.Token, nil
}

func NewSession(config Config) (*Session, error) {
	session := new(Session)

	var err error
	if session.token, err = fecthAuthToken(config); err != nil {
		return nil, err
	}

	session.host = config.GetHost()

	return session, nil
}

func (session *Session) String() string {
	return fmt.Sprintf("FogBugzSession for token %s", session.token)
}
<commit_msg>Use a POST request to file bugs<commit_after>package fogbugz

import (
	"encoding/xml"
	"errors"
	"fmt"
	"net/http"
	"net/url"
)

type Session struct {
	host  string
	token string
}

type Config interface {
	GetEmail() string
	GetPassword() string
	GetHost() string
}

type errorCodeTag struct {
	ErrorCode int    `xml:"code,attr"`
	ErrorDesc string `xml:",chardata"`
}

type caseTag struct {
	BugNumber  string `xml:"ixBug,attr"`
	Operations string
}

func (session *Session) FileBug(project string, area string, title string, content string) (string, error) {
	values := url.Values{}
	values.Set("cmd", "new")
	values.Set("token", session.token)
	values.Set("sProject", project)
	values.Set("sArea", area)
	values.Set("sTitle", title)
	values.Set("sEvent", content)
	url := &url.URL{"https", "", nil, session.host, "/api.asp", "", ""}

	resp, err := http.PostForm(url.String(), values)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		err = errors.New(fmt.Sprintf("Failed to create bug report: %s", resp.Status))
		return "", err
	}

	type Response struct {
		XMLName xml.Name     `xml:"response"`
		Case    caseTag      `xml:"case"`
		Error   errorCodeTag `xml:"error"`
	}

	var r Response
	dec := xml.NewDecoder(resp.Body)
	err = dec.Decode(&r)
	if err != nil {
		return "", err
	}

	if r.Error.ErrorCode != 0 {
		return "", errors.New(fmt.Sprintf("Fogbugz error %d: %s", r.Error.ErrorCode, r.Error.ErrorDesc))
	}

	return fmt.Sprintf("https://%s/default.asp?%s", session.host, r.Case.BugNumber), nil
}

func fecthAuthToken(config Config) (string, error) {
	values := url.Values{}
	values.Set("cmd", "logon")
	values.Set("email", config.GetEmail())
	values.Set("password", config.GetPassword())
	url := &url.URL{"https", "", nil, config.GetHost(), "/api.asp", values.Encode(), ""}

	resp, err := http.Get(url.String())
	if err != nil {
		return "", err
	}

	defer resp.Body.Close()

	type Response struct {
		XMLName xml.Name     `xml:"response"`
		Token   string       `xml:"token"`
		Error   errorCodeTag `xml:"error"`
	}

	var r Response
	dec := xml.NewDecoder(resp.Body)
	err = dec.Decode(&r)
	if err != nil {
		return "", err
	}

	if r.Error.ErrorCode != 0 {
		return "", errors.New(fmt.Sprintf("Fogbugz error %d: %s", r.Error.ErrorCode, r.Error.ErrorDesc))
	}

	return r.Token, nil
}

func NewSession(config Config) (*Session, error) {
	session := new(Session)

	var err error
	if session.token, err = fecthAuthToken(config); err != nil {
		return nil, err
	}

	session.host = config.GetHost()

	return session, nil
}

func (session *Session) String() string {
	return fmt.Sprintf("FogBugzSession for token %s", session.token)
}
<|endoftext|>


<commit_before>package forward

import (
	"time"
	"bytes"
	"bufio"
	"io/ioutil"
	"net"
	"errors"
	"strings"
	"net/http"
	"net/http/httputil"

	"github.com/rookmoot/proxifier/logger"
)

type Remote interface {
	GetRemoteAddr() (*net.TCPAddr, error)
}

type User interface {
	IsConnected() bool
}

type Forward struct {
	log           logger.Logger

	conn          net.Conn
	remote	      net.Conn

	user	      User

	request      *http.Request
	response     *http.Response

	authHandler   OnAuthenticationHandlerFunc
	remoteHandler OnToHandlerFunc
	httpHandler   []OnHandlerFunc

	MaxRetry      int
	data          interface{}
}

var unauthorizedMsg = []byte("Proxy Authentication Required")
var errorMsg        = []byte("Proxy internal error")

type OnAuthenticationHandlerFunc func(req *http.Request, username string, password string) (User, error)
type OnToHandlerFunc func(req *http.Request) (Remote, error)
type OnHandlerFunc func(resp *http.Response, req *http.Request) (error)

func New(conn net.Conn, log logger.Logger) (*Forward, error) {
	fwd := Forward{
		conn: conn,
		remote: nil,
		log: log,
		MaxRetry: 1,
	}
	return &fwd, nil
}

func (fwd *Forward)SetData(data interface{}) {
	fwd.data = data
}

func (fwd *Forward)GetData() interface{} {
	return fwd.data
}

func (fwd *Forward)GetUser() User {
	return fwd.user
}

func (fwd *Forward)Close() {
	fwd.conn.Close()
	if fwd.remote != nil {
		fwd.remote.Close()
	}
}

func (fwd *Forward)On(cb OnHandlerFunc) {
	fwd.httpHandler = append(fwd.httpHandler, cb)
}

func (fwd *Forward)OnAuthentication(cb OnAuthenticationHandlerFunc) {
	fwd.authHandler = cb
}

func (fwd *Forward)OnSelectRemote(cb OnToHandlerFunc) {
	fwd.remoteHandler = cb
}

func (fwd *Forward)Forward() error {
	// read client request from socket
	// Here we can check for proxy authentication
	// and others headers sent like X-PROXIFIER-
	// then, we NEED to remove those header to
	// send only clean headers
	err := fwd.readRequest()
	if err != nil {
		fwd.createErrorResponse(500, []byte("Failed to read sent request."))
		return err
	}

	// Forward the request to select proxy remote
	// and get the according response
	err = fwd.forward()
	if err != nil {
		fwd.createErrorResponse(500, []byte(err.Error()))
		return err
	}

	// Send request and response to callbacks
	// The user can manage request and response
	// before they are sent back.
	for _, cb := range fwd.httpHandler {
		err = cb(fwd.response, fwd.request)
		if err != nil {
			return err
		}
	}

	// Send back remote proxy host response to initial
	// client.
	return fwd.response.Write(fwd.conn)
}

func (fwd *Forward)getRemoteConn(timeout time.Duration) error {
	if fwd.remoteHandler == nil {
		return errors.New("No callback for fwd.OnSelectRemote() found. Can't perform request.")
	}

	remote, err := fwd.remoteHandler(fwd.request)
	if err != nil {
		return err
	}

	remote_addr, err := remote.GetRemoteAddr()
	if err != nil {
		return err
	}

	fwd.remote, err = net.DialTimeout("tcp", remote_addr.String(), timeout)
	if err != nil {
		return err
	}
	fwd.remote.SetDeadline(time.Now().Add(timeout))

	return nil
}

func (fwd *Forward)forward() error {
	if (fwd.MaxRetry) < 0 {
		return errors.New("Max retry reached.")
	}
	fwd.MaxRetry--

	timeout_delta := 900 * time.Millisecond;
	err := fwd.getRemoteConn(timeout_delta)
	if err != nil {
		return err
	}

	// Forward request to remote proxy host.
	err = fwd.request.WriteProxy(fwd.remote)
	if err != nil {
		return err
	}

	// Read response from remote proxy host.
	// Here we NEED to check status code and other stuff
	// to get clean request and be able to serve only
	// valid content.
	// Status code to check :
	//   301 -> redirection
	//   4/5xx -> Check for error and retry
	err = fwd.readResponse()
	if err != nil {
		return err
	}

	return nil
}

func (fwd *Forward)authenticate() error {
	if fwd.authHandler == nil {
		return nil
	}

	username, password, ok := fwd.ProxyBasicAuth()
	if ok == false {
		return errors.New("No authentication header found.")
	}

	_user, err := fwd.authHandler(fwd.request, username, password)
	if _user == nil {
		return errors.New("Returned nil user during authentication")
	}

	if err != nil {
		return err
	}

	if _user.IsConnected() == false {
		return errors.New("Failed to log user in. No user found.")
	}

	fwd.user = _user
	return nil
}

func (fwd *Forward)readRequest() error {
	req, err := http.ReadRequest(bufio.NewReader(fwd.conn))
	if err != nil {
		return err
	}
	fwd.request = req

	dump, err := httputil.DumpRequest(fwd.request, false)
	if err == nil {
		fwd.log.Trace("Request :\n%v", string(dump))
	}

	err = fwd.filterRequest()
	if err != nil {
		return err
	}
	return nil
}

func (fwd *Forward)filterRequest() error {
	if fwd.request == nil {
		return errors.New("Can't filter forward request. Request is nil.")
	}

	// clean up necessary stuff
	fwd.request.Header.Del("Connection")
	fwd.request.Header.Del("Accept-Encoding")

	// check for headers specifics operations
	for k, _ := range fwd.request.Header {
		if (strings.HasPrefix(k, "Proxy-")) {
			// Handles the following headers and remove them
			// Proxy-Authorization: Basic dGVzdDp0ZXN0
			// Proxy-Connection: Keep-Alive

			switch k {
  			   case "Proxy-Authorization":
				err := fwd.authenticate()
				if err != nil {
					fwd.createErrorResponse(407, unauthorizedMsg)
					return err
				}

			   default:
			}

			fwd.request.Header.Del(k)
		}

		if (strings.HasPrefix(k, "X-Proxifier")) {
			switch k {
			   // X-Proxifier-Https:
			   // This header made the http initial request to be transformed
			   // to an https request.
    			   case "X-Proxifier-Https":
				fwd.request.URL.Scheme = "https"
				r := strings.NewReplacer("http://", "https://")
				fwd.request.RequestURI = r.Replace(fwd.request.RequestURI)
			   default:
			}

			fwd.request.Header.Del(k)
		}
	}
	return nil
}

func (fwd *Forward)readResponse() error {
	resp, err := http.ReadResponse(bufio.NewReader(fwd.remote), fwd.request);
	if err != nil {
		return err
	}
	fwd.response = resp

	dump, err := httputil.DumpResponse(fwd.response, false)
	if err == nil {
		fwd.log.Trace("Response :\n%v", string(dump))
	}

	err = fwd.filterResponse()
	if err != nil {
		return err
	}
	return nil
}

func (fwd *Forward)filterResponse() error {
        if fwd.response == nil {
		return errors.New("Can't filter forwarded response. Response is nil.")
	}

	// In case of redirect, perform the redirect.
	if fwd.response.StatusCode == 301 {
		url, err := fwd.response.Location()
		if err != nil {
			return err
		}
		fwd.request.URL = url
		fwd.request.RequestURI = url.String()
		fwd.forward()
	}

	return nil
}

func (fwd *Forward)createErrorResponse(code int, reason []byte) {
	reason = append(reason, byte('\n'))
	fwd.response = &http.Response{
		StatusCode:    code,
		ProtoMajor:    1,
		ProtoMinor:    1,
		Request:       fwd.request,
		Body:          ioutil.NopCloser(bytes.NewBuffer(reason)),
		ContentLength: int64(len(reason)),
	}

	if code == 407 {
		// Automaticaly add a Proxy-Authenticate Header when the client need to
		// be logged.
		fwd.response.Header = http.Header{"Proxy-Authenticate": []string{"Basic realm="}};
	}

	fwd.response.Write(fwd.conn)
}
<commit_msg>Adding a better way to handle user rate limit. This is always an interface and you can use any rate limiter.<commit_after>package forward

import (
	"time"
	"bytes"
	"bufio"
	"io/ioutil"
	"net"
	"errors"
	"strings"
	"strconv"
	"net/http"
	"net/http/httputil"

	"github.com/rookmoot/proxifier/logger"
)

type Remote interface {
	GetRemoteAddr() (*net.TCPAddr, error)
}

type User interface {
	Limit() (count, reset int64, allow bool)
	IsConnected() bool
}

type Forward struct {
	log           logger.Logger

	conn          net.Conn
	remote	      net.Conn

	user	      User

	request      *http.Request
	response     *http.Response

	authHandler   OnAuthenticationHandlerFunc
	remoteHandler OnToHandlerFunc
	httpHandler   []OnHandlerFunc

	MaxRetry      int
	data          interface{}

	rate int64
	reset int64
	allowed bool
}

var unauthorizedMsg = []byte("Proxy Authentication Required")
var errorMsg        = []byte("Proxy internal error")

type OnAuthenticationHandlerFunc func(req *http.Request, username string, password string) (User, error)
type OnToHandlerFunc func(req *http.Request) (Remote, error)
type OnHandlerFunc func(resp *http.Response, req *http.Request) (error)

func New(conn net.Conn, log logger.Logger) (*Forward, error) {
	fwd := Forward{
		conn: conn,
		remote: nil,
		log: log,
		MaxRetry: 1,
	}
	return &fwd, nil
}

func (fwd *Forward)SetData(data interface{}) {
	fwd.data = data
}

func (fwd *Forward)GetData() interface{} {
	return fwd.data
}

func (fwd *Forward)GetUser() User {
	return fwd.user
}

func (fwd *Forward)Close() {
	fwd.conn.Close()
	if fwd.remote != nil {
		fwd.remote.Close()
	}
}

func (fwd *Forward)On(cb OnHandlerFunc) {
	fwd.httpHandler = append(fwd.httpHandler, cb)
}

func (fwd *Forward)OnAuthentication(cb OnAuthenticationHandlerFunc) {
	fwd.authHandler = cb
}

func (fwd *Forward)OnSelectRemote(cb OnToHandlerFunc) {
	fwd.remoteHandler = cb
}

func (fwd *Forward)Forward() error {
	// read client request from socket
	// Here we can check for proxy authentication
	// and others headers sent like X-PROXIFIER-
	// then, we NEED to remove those header to
	// send only clean headers
	err := fwd.readRequest()
	if err != nil {
		fwd.createErrorResponse(500, []byte("Failed to read sent request."))
		return err
	}

	// check for Ratelimited user acccess
	if fwd.user != nil && fwd.user.IsConnected() {
		fwd.rate, fwd.reset, fwd.allowed = fwd.user.Limit()
		if fwd.allowed == false {
			fwd.createErrorResponse(400, []byte("User rate limits exceeded."))
		}
	}

	// Forward the request to select proxy remote
	// and get the according response
	err = fwd.forward()
	if err != nil {
		fwd.createErrorResponse(500, []byte(err.Error()))
		return err
	}

	// Send request and response to callbacks
	// The user can manage request and response
	// before they are sent back.
	for _, cb := range fwd.httpHandler {
		err = cb(fwd.response, fwd.request)
		if err != nil {
			return err
		}
	}

	// Send back remote proxy host response to initial
	// client.
	return fwd.response.Write(fwd.conn)
}

func (fwd *Forward)getRemoteConn(timeout time.Duration) error {
	if fwd.remoteHandler == nil {
		return errors.New("No callback for fwd.OnSelectRemote() found. Can't perform request.")
	}

	remote, err := fwd.remoteHandler(fwd.request)
	if err != nil {
		return err
	}

	remote_addr, err := remote.GetRemoteAddr()
	if err != nil {
		return err
	}

	fwd.remote, err = net.DialTimeout("tcp", remote_addr.String(), timeout)
	if err != nil {
		return err
	}
	fwd.remote.SetDeadline(time.Now().Add(timeout))

	return nil
}

func (fwd *Forward)forward() error {
	if (fwd.MaxRetry) < 0 {
		return errors.New("Max retry reached.")
	}
	fwd.MaxRetry--

	timeout_delta := 5 * time.Second;
	err := fwd.getRemoteConn(timeout_delta)
	if err != nil {
		return err
	}

	// Forward request to remote proxy host.
	err = fwd.request.WriteProxy(fwd.remote)
	if err != nil {
		return err
	}

	// Read response from remote proxy host.
	// Here we NEED to check status code and other stuff
	// to get clean request and be able to serve only
	// valid content.
	// Status code to check :
	//   301 -> redirection
	//   4/5xx -> Check for error and retry
	err = fwd.readResponse()
	if err != nil {
		return err
	}

	return nil
}

func (fwd *Forward)authenticate() error {
	if fwd.authHandler == nil {
		return nil
	}

	username, password, ok := fwd.ProxyBasicAuth()
	if ok == false {
		return errors.New("No authentication header found.")
	}

	_user, err := fwd.authHandler(fwd.request, username, password)
	if _user == nil {
		return errors.New("Returned nil user during authentication")
	}

	if err != nil {
		return err
	}

	if _user.IsConnected() == false {
		return errors.New("Failed to log user in. No user found.")
	}

	fwd.user = _user
	return nil
}

func (fwd *Forward)readRequest() error {
	req, err := http.ReadRequest(bufio.NewReader(fwd.conn))
	if err != nil {
		return err
	}
	fwd.request = req

	dump, err := httputil.DumpRequest(fwd.request, false)
	if err == nil {
		fwd.log.Trace("Request :\n%v", string(dump))
	}

	err = fwd.filterRequest()
	if err != nil {
		return err
	}
	return nil
}

func (fwd *Forward)filterRequest() error {
	if fwd.request == nil {
		return errors.New("Can't filter forward request. Request is nil.")
	}

	// clean up necessary stuff
	fwd.request.Header.Del("Connection")
	fwd.request.Header.Del("Accept-Encoding")

	// check for headers specifics operations
	for k, _ := range fwd.request.Header {
		if (strings.HasPrefix(k, "Proxy-")) {
			// Handles the following headers and remove them
			// Proxy-Authorization: Basic dGVzdDp0ZXN0
			// Proxy-Connection: Keep-Alive

			switch k {
  			   case "Proxy-Authorization":
				err := fwd.authenticate()
				if err != nil {
					fwd.createErrorResponse(407, unauthorizedMsg)
					return err
				}

			   default:
			}

			fwd.request.Header.Del(k)
		}

		if (strings.HasPrefix(k, "X-Proxifier")) {
			switch k {
			   // X-Proxifier-Https:
			   // This header made the http initial request to be transformed
			   // to an https request.
    			   case "X-Proxifier-Https":
				fwd.request.URL.Scheme = "https"
				r := strings.NewReplacer("http://", "https://")
				fwd.request.RequestURI = r.Replace(fwd.request.RequestURI)
			   default:
			}

			fwd.request.Header.Del(k)
		}
	}
	return nil
}

func (fwd *Forward)readResponse() error {
	resp, err := http.ReadResponse(bufio.NewReader(fwd.remote), fwd.request);
	if err != nil {
		return err
	}
	fwd.response = resp

	dump, err := httputil.DumpResponse(fwd.response, false)
	if err == nil {
		fwd.log.Trace("Response :\n%v", string(dump))
	}

	err = fwd.filterResponse()
	if err != nil {
		return err
	}
	return nil
}

func (fwd *Forward)filterResponse() error {
        if fwd.response == nil {
		return errors.New("Can't filter forwarded response. Response is nil.")
	}

	// In case of redirect, perform the redirect.
	if fwd.response.StatusCode == 301 {
		url, err := fwd.response.Location()
		if err != nil {
			return err
		}
		fwd.request.URL = url
		fwd.request.RequestURI = url.String()
		fwd.forward()
	}

//	if fwd.response.StatusCode != 200 {
	fwd.response.Header.Set("X-RateLimit-Limit", strconv.FormatInt(60, 10))
	fwd.response.Header.Set("X-RateLimit-Remaining", strconv.FormatInt((60 - fwd.rate), 10))
	fwd.response.Header.Set("X-RateLimit-Reset", strconv.FormatInt(fwd.reset, 10))
//	}

	return nil
}

func (fwd *Forward)createErrorResponse(code int, reason []byte) {
	reason = append(reason, byte('\n'))
	fwd.response = &http.Response{
		StatusCode:    code,
		ProtoMajor:    1,
		ProtoMinor:    1,
		Request:       fwd.request,
		Body:          ioutil.NopCloser(bytes.NewBuffer(reason)),
		ContentLength: int64(len(reason)),
	}

	if code == 407 {
		// Automaticaly add a Proxy-Authenticate Header when the client need to
		// be logged.
		fwd.response.Header = http.Header{"Proxy-Authenticate": []string{"Basic realm="}};
	}

	fwd.response.Write(fwd.conn)
}
<|endoftext|>


<commit_before>// +build linux

package linux

import (
	"os"
	"testing"
)

func TestInterfaceKey(t *testing.T) {
	g := &InterfaceGenerator{}

	if g.Key() != "interface" {
		t.Error("key should be interface")
	}
}

func TestInterfaceGenerate(t *testing.T) {
	g := &InterfaceGenerator{}
	value, err := g.Generate()
	if err != nil {
		t.Error("should not raise error")
	}

	interfaces, typeOk := value.([]map[string]interface{})
	if !typeOk {
		t.Errorf("value should be slice of map", value)
	}
	if len(interfaces) == 0 {
		t.Error("should have at least 1 interface")
	}

	iface := interfaces[0]
	if _, ok := iface["ipAddress"]; !ok {
		t.Error("interface should have ipAddress")
	}
	if _, ok := iface["macAddress"]; !ok {
		t.Error("interface should have macAddress")
	}
	if _, ok := iface["netmask"]; !ok {
		t.Error("interface should have netmask")
	}
	if _, ok := iface["address"]; !ok {
		t.Error("interface should have address")
	}
	if _, ok := iface["defaultGateway"]; !ok {
		t.Error("interface should have defaultGateway")
	}
}

func TestGenerateByIpCommand(t *testing.T) {
	if _, err := os.Stat("/etc/fedora-release"); err == nil {
		t.Skip("The OS seems to be Fedora. Skipping interface test for now")
	}

	g := &InterfaceGenerator{}
	interfaces, err := g.generateByIpCommand()
	if err != nil {
		t.Error("should not raise error")
	}

	name := "eth0"
	if _, ok := interfaces[name]; !ok {
		t.Error("should have interfaces")
	}

	iface := interfaces[name]
	if len(iface) == 0 {
		t.Error("should have item")
	}
	if _, ok := iface["ipAddress"]; !ok {
		t.Error("interface should have ipAddress")
	}
	if _, ok := iface["macAddress"]; !ok {
		t.Error("interface should have macAddress")
	}
	if _, ok := iface["netmask"]; !ok {
		t.Error("interface should have netmask")
	}
	if _, ok := iface["address"]; !ok {
		t.Error("interface should have address")
	}
	if _, ok := iface["defaultGateway"]; !ok {
		t.Error("interface should have defaultGateway")
	}
}

func TestGenerateByIfconfigCommand(t *testing.T) {
	g := &InterfaceGenerator{}
	interfaces, err := g.generateByIfconfigCommand()
	if err != nil {
		t.Log("Skip: should not raise error")
	}

	name := "eth0"
	if _, ok := interfaces[name]; !ok {
		t.Log("Skip: should have interfaces")
	}

	iface := interfaces[name]
	if len(iface) == 0 {
		t.Log("Skip: should have item")
	}
	if _, ok := iface["ipAddress"]; !ok {
		t.Log("Skip: interface should have ipAddress")
	}
	if _, ok := iface["macAddress"]; !ok {
		t.Log("Skip: interface should have macAddress")
	}
	if _, ok := iface["netmask"]; !ok {
		t.Log("Skip: interface should have netmask")
	}
	if _, ok := iface["address"]; !ok {
		t.Log("Skip: interface should have address")
	}
	if _, ok := iface["defaultGateway"]; !ok {
		t.Log("Skip: interface should have defaultGateway")
	}
}
<commit_msg>skip spec/interface_test in travis for now<commit_after>// +build linux

package linux

import (
	"os"
	"testing"
)

func TestInterfaceKey(t *testing.T) {
	g := &InterfaceGenerator{}

	if g.Key() != "interface" {
		t.Error("key should be interface")
	}
}

func TestInterfaceGenerate(t *testing.T) {
	g := &InterfaceGenerator{}
	value, err := g.Generate()
	if err != nil {
		t.Error("should not raise error")
	}

	interfaces, typeOk := value.([]map[string]interface{})
	if !typeOk {
		t.Errorf("value should be slice of map", value)
	}

	if os.Getenv("TRAVIS") != "" {
		t.Skip("Skip in Travis for now")
	}

	if len(interfaces) == 0 {
		t.Error("should have at least 1 interface")
	}

	iface := interfaces[0]
	if _, ok := iface["ipAddress"]; !ok {
		t.Error("interface should have ipAddress")
	}
	if _, ok := iface["macAddress"]; !ok {
		t.Error("interface should have macAddress")
	}
	if _, ok := iface["netmask"]; !ok {
		t.Error("interface should have netmask")
	}
	if _, ok := iface["address"]; !ok {
		t.Error("interface should have address")
	}
	if _, ok := iface["defaultGateway"]; !ok {
		t.Error("interface should have defaultGateway")
	}
}

func TestGenerateByIpCommand(t *testing.T) {
	if _, err := os.Stat("/etc/fedora-release"); err == nil {
		t.Skip("The OS seems to be Fedora. Skipping interface test for now")
	}

	g := &InterfaceGenerator{}
	interfaces, err := g.generateByIpCommand()
	if err != nil {
		t.Error("should not raise error")
	}

	name := "eth0"
	if _, ok := interfaces[name]; !ok {
		t.Error("should have interfaces")
	}

	iface := interfaces[name]
	if len(iface) == 0 {
		t.Error("should have item")
	}
	if _, ok := iface["ipAddress"]; !ok {
		t.Error("interface should have ipAddress")
	}
	if _, ok := iface["macAddress"]; !ok {
		t.Error("interface should have macAddress")
	}
	if _, ok := iface["netmask"]; !ok {
		t.Error("interface should have netmask")
	}
	if _, ok := iface["address"]; !ok {
		t.Error("interface should have address")
	}
	if _, ok := iface["defaultGateway"]; !ok {
		t.Error("interface should have defaultGateway")
	}
}

func TestGenerateByIfconfigCommand(t *testing.T) {
	g := &InterfaceGenerator{}
	interfaces, err := g.generateByIfconfigCommand()
	if err != nil {
		t.Log("Skip: should not raise error")
	}

	name := "eth0"
	if _, ok := interfaces[name]; !ok {
		t.Log("Skip: should have interfaces")
	}

	iface := interfaces[name]
	if len(iface) == 0 {
		t.Log("Skip: should have item")
	}
	if _, ok := iface["ipAddress"]; !ok {
		t.Log("Skip: interface should have ipAddress")
	}
	if _, ok := iface["macAddress"]; !ok {
		t.Log("Skip: interface should have macAddress")
	}
	if _, ok := iface["netmask"]; !ok {
		t.Log("Skip: interface should have netmask")
	}
	if _, ok := iface["address"]; !ok {
		t.Log("Skip: interface should have address")
	}
	if _, ok := iface["defaultGateway"]; !ok {
		t.Log("Skip: interface should have defaultGateway")
	}
}
<|endoftext|>


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

package lzma

import (
	"fmt"
	"io"
)

// buffer provides a circular buffer. The type supports the io.Writer
// interface and other functions required to implement a dictionary.
//
// The top offset tracks the position of the buffer in the byte stream
// covered. The bottom offset marks the bottom of the buffer. The
// writeLimit marks the limit for additional writes.
//
// Change top only with the setTop function.
type buffer struct {
	data       []byte
	bottom     int64 // bottom == max(top - len(data), 0)
	top        int64
	writeLimit int64
}

// maxLimit provides the maximum value. Setting the writeLimit to
// this value disables the writeLimit for all practical purposes.
const maxLimit = 1<<63 - 1

// toInt converts an int64 value to an int value. If the number is not
// representable as int, errInt64 is returned.
func toInt(n int64) (int, error) {
	k := int(n)
	if int64(k) != n {
		return 0, errInt64
	}
	return k, nil
}

// newBuffer creates a new buffer.
func newBuffer(capacity int64) (b *buffer, err error) {
	if capacity < 0 {
		return nil, negError{"capacity", capacity}
	}
	c, err := toInt(capacity)
	if err != nil {
		return nil, lzmaError{fmt.Sprintf(
			"capacity %d cannot be represented as int", capacity)}
	}
	b = &buffer{data: make([]byte, c), writeLimit: maxLimit}
	return b, nil
}

// capacity returns the max)imum capacity of the buffer.
func (b *buffer) capacity() int {
	return len(b.data)
}

// length returns the actual length of the buffer.
func (b *buffer) length() int {
	return int(b.top - b.bottom)
}

// setTop sets the top and bottom offset. Any modification of the top
// offset must use this method.
func (b *buffer) setTop(off int64) {
	if off < 0 {
		panic("b.Top overflow?")
	}
	if off > b.writeLimit {
		panic("off exceeds writeLimit")
	}
	b.top = off
	b.bottom = off - int64(len(b.data))
	if b.bottom < 0 {
		b.bottom = 0
	}
}

// index converts a byte stream offset into an index of the data field.
func (b *buffer) index(off int64) int {
	if off < 0 {
		panic(negError{"off", off})
	}
	return int(off % int64(len(b.data)))
}

// Write writes a byte slice into the buffer. It satisfies the io.Write
// interface.
func (b *buffer) Write(p []byte) (n int, err error) {
	if len(p) == 0 {
		return
	}
	var m int
	off := b.top
	end := add(off, int64(len(p)))
	if end > b.writeLimit {
		m = int(b.writeLimit - off)
		p = p[:m]
		err = errWriteLimit
	}
	m = len(p) - len(b.data)
	if m > 0 {
		off += int64(m)
		p = p[m:]
	}
	for len(p) > 0 {
		m = copy(b.data[b.index(off):], p)
		off += int64(m)
		p = p[m:]
	}
	n = int(off - b.top)
	b.setTop(off)
	return n, err
}

// WriteByte writes a single byte into the buffer. The method satisfies
// the io.ByteWriter interface.
func (b *buffer) WriteByte(c byte) error {
	if b.top >= b.writeLimit {
		return errWriteLimit
	}
	b.data[b.index(b.top)] = c
	b.setTop(b.top + 1)
	return nil
}

// writeSlice returns a slice from the buffer for direct writing of
// data. Note that depending of top in the ring buffer the array p might
// be smaller then end-buf.top.
func (b *buffer) writeSlice(end int64) (p []byte, err error) {
	if end <= b.top {
		if end < b.top {
			return nil, lzmaError{fmt.Sprintf("end=%d less than top=%d", end, b.top)}
		}
		return nil, errAgain
	}
	if end > b.writeLimit {
		return nil, errWriteLimit
	}
	s, e := b.index(b.top), b.index(end)
	if s < e {
		p = b.data[s:e]
	} else {
		p = b.data[s:]
	}
	return p, nil
}

// writeRangeTo is a helper function that writes all data between off
// and end to the writer. The function doesn't check the arguments.
func (b *buffer) writeRangeTo(off, end int64, w io.Writer) (written int, err error) {
	// assume that arguments are correct
	start := off
	e := b.index(end)
	for off < end {
		s := b.index(off)
		var q []byte
		if s < e {
			q = b.data[s:e]
		} else {
			q = b.data[s:]
		}
		var k int
		k, err = w.Write(q)
		off += int64(k)
		if err != nil {
			break
		}
	}
	return int(off - start), err
}

// readByteAt returns the byte at the given offset. If off is not in the
// range [b.bottom, b.top) a rangeError is returned unless off equals
// b.top. In that case errAgain is returned.
func (b *buffer) readByteAt(off int64) (c byte, err error) {
	if !(b.bottom <= off && off < b.top) {
		if off == b.top {
			return 0, errAgain
		}
		return 0, rangeError{"offset", off}
	}
	c = b.data[b.index(off)]
	return c, nil
}

// writeRepAt writes a repetition into the buffer. Obviously the method is
// used to handle matches during decoding the LZMA stream.
func (b *buffer) writeRepAt(n int, off int64) (written int, err error) {
	if n < 0 {
		return 0, negError{"n", n}
	}
	if !(b.bottom <= off && off < b.top) {
		return 0, rangeError{"off", off}
	}

	start, end := off, add(off, int64(n))
	if end > b.writeLimit {
		return 0, errWriteLimit
	}
	for off < end {
		var next int64
		if b.top < end {
			next = b.top
		} else {
			next = end
		}
		var k int
		k, err = b.writeRangeTo(off, next, b)
		off += int64(k)
		if err != nil {
			break
		}
	}
	return int(off - start), err
}

// readAtBuffer provides a wrapper for the p buffer of the ReadAt
// function.
type readAtBuffer struct {
	p []byte
}

// Write satisfies the Writer interface for readAtBuffer.
func (b *readAtBuffer) Write(p []byte) (n int, err error) {
	n = copy(b.p, p)
	b.p = b.p[n:]
	if n < len(p) {
		err = errSpace
	}
	return
}

// ReadAt provides the ReaderAt interface.
func (b *buffer) ReadAt(p []byte, off int64) (n int, err error) {
	if !(b.bottom <= off && off <= b.top) {
		return 0, rangeError{"off", off}
	}
	end := add(off, int64(len(p)))
	if end > b.top {
		end = b.top
	}
	n, err = b.writeRangeTo(off, end, &readAtBuffer{p})
	if err == errSpace {
		err = nil
	}
	return
}

// equalBytes count the equal bytes at off1 and off2 until max is reached.
func (b *buffer) equalBytes(off1, off2 int64, max int) int {
	if off1 < b.bottom || off2 < b.bottom || max <= 0 {
		return 0
	}
	m := int64(max)
	k := b.top - off1
	if k < m {
		if k <= 0 {
			return 0
		}
		m = k
	}
	k = b.top - off2
	if k < m {
		if k <= 0 {
			return 0
		}
		m = k
	}
	for k = 0; k < m; k++ {
		i, j := b.index(off1+k), b.index(off2+k)
		if b.data[i] != b.data[j] {
			break
		}
	}
	return int(k)
}

// resets the buffer to its original values.
func (b *buffer) reset() {
	b.top = 0
	b.bottom = 0
	b.writeLimit = maxLimit
}
<commit_msg>lzma: fixed a typo in the documentation of buffer.capacity<commit_after>// Copyright 2015 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lzma

import (
	"fmt"
	"io"
)

// buffer provides a circular buffer. The type supports the io.Writer
// interface and other functions required to implement a dictionary.
//
// The top offset tracks the position of the buffer in the byte stream
// covered. The bottom offset marks the bottom of the buffer. The
// writeLimit marks the limit for additional writes.
//
// Change top only with the setTop function.
type buffer struct {
	data       []byte
	bottom     int64 // bottom == max(top - len(data), 0)
	top        int64
	writeLimit int64
}

// maxLimit provides the maximum value. Setting the writeLimit to
// this value disables the writeLimit for all practical purposes.
const maxLimit = 1<<63 - 1

// toInt converts an int64 value to an int value. If the number is not
// representable as int, errInt64 is returned.
func toInt(n int64) (int, error) {
	k := int(n)
	if int64(k) != n {
		return 0, errInt64
	}
	return k, nil
}

// newBuffer creates a new buffer.
func newBuffer(capacity int64) (b *buffer, err error) {
	if capacity < 0 {
		return nil, negError{"capacity", capacity}
	}
	c, err := toInt(capacity)
	if err != nil {
		return nil, lzmaError{fmt.Sprintf(
			"capacity %d cannot be represented as int", capacity)}
	}
	b = &buffer{data: make([]byte, c), writeLimit: maxLimit}
	return b, nil
}

// capacity returns the maximum capacity of the buffer.
func (b *buffer) capacity() int {
	return len(b.data)
}

// length returns the actual length of the buffer.
func (b *buffer) length() int {
	return int(b.top - b.bottom)
}

// setTop sets the top and bottom offset. Any modification of the top
// offset must use this method.
func (b *buffer) setTop(off int64) {
	if off < 0 {
		panic("b.Top overflow?")
	}
	if off > b.writeLimit {
		panic("off exceeds writeLimit")
	}
	b.top = off
	b.bottom = off - int64(len(b.data))
	if b.bottom < 0 {
		b.bottom = 0
	}
}

// index converts a byte stream offset into an index of the data field.
func (b *buffer) index(off int64) int {
	if off < 0 {
		panic(negError{"off", off})
	}
	return int(off % int64(len(b.data)))
}

// Write writes a byte slice into the buffer. It satisfies the io.Write
// interface.
func (b *buffer) Write(p []byte) (n int, err error) {
	if len(p) == 0 {
		return
	}
	var m int
	off := b.top
	end := add(off, int64(len(p)))
	if end > b.writeLimit {
		m = int(b.writeLimit - off)
		p = p[:m]
		err = errWriteLimit
	}
	m = len(p) - len(b.data)
	if m > 0 {
		off += int64(m)
		p = p[m:]
	}
	for len(p) > 0 {
		m = copy(b.data[b.index(off):], p)
		off += int64(m)
		p = p[m:]
	}
	n = int(off - b.top)
	b.setTop(off)
	return n, err
}

// WriteByte writes a single byte into the buffer. The method satisfies
// the io.ByteWriter interface.
func (b *buffer) WriteByte(c byte) error {
	if b.top >= b.writeLimit {
		return errWriteLimit
	}
	b.data[b.index(b.top)] = c
	b.setTop(b.top + 1)
	return nil
}

// writeSlice returns a slice from the buffer for direct writing of
// data. Note that depending of top in the ring buffer the array p might
// be smaller then end-buf.top.
func (b *buffer) writeSlice(end int64) (p []byte, err error) {
	if end <= b.top {
		if end < b.top {
			return nil, lzmaError{fmt.Sprintf("end=%d less than top=%d", end, b.top)}
		}
		return nil, errAgain
	}
	if end > b.writeLimit {
		return nil, errWriteLimit
	}
	s, e := b.index(b.top), b.index(end)
	if s < e {
		p = b.data[s:e]
	} else {
		p = b.data[s:]
	}
	return p, nil
}

// writeRangeTo is a helper function that writes all data between off
// and end to the writer. The function doesn't check the arguments.
func (b *buffer) writeRangeTo(off, end int64, w io.Writer) (written int, err error) {
	// assume that arguments are correct
	start := off
	e := b.index(end)
	for off < end {
		s := b.index(off)
		var q []byte
		if s < e {
			q = b.data[s:e]
		} else {
			q = b.data[s:]
		}
		var k int
		k, err = w.Write(q)
		off += int64(k)
		if err != nil {
			break
		}
	}
	return int(off - start), err
}

// readByteAt returns the byte at the given offset. If off is not in the
// range [b.bottom, b.top) a rangeError is returned unless off equals
// b.top. In that case errAgain is returned.
func (b *buffer) readByteAt(off int64) (c byte, err error) {
	if !(b.bottom <= off && off < b.top) {
		if off == b.top {
			return 0, errAgain
		}
		return 0, rangeError{"offset", off}
	}
	c = b.data[b.index(off)]
	return c, nil
}

// writeRepAt writes a repetition into the buffer. Obviously the method is
// used to handle matches during decoding the LZMA stream.
func (b *buffer) writeRepAt(n int, off int64) (written int, err error) {
	if n < 0 {
		return 0, negError{"n", n}
	}
	if !(b.bottom <= off && off < b.top) {
		return 0, rangeError{"off", off}
	}

	start, end := off, add(off, int64(n))
	if end > b.writeLimit {
		return 0, errWriteLimit
	}
	for off < end {
		var next int64
		if b.top < end {
			next = b.top
		} else {
			next = end
		}
		var k int
		k, err = b.writeRangeTo(off, next, b)
		off += int64(k)
		if err != nil {
			break
		}
	}
	return int(off - start), err
}

// readAtBuffer provides a wrapper for the p buffer of the ReadAt
// function.
type readAtBuffer struct {
	p []byte
}

// Write satisfies the Writer interface for readAtBuffer.
func (b *readAtBuffer) Write(p []byte) (n int, err error) {
	n = copy(b.p, p)
	b.p = b.p[n:]
	if n < len(p) {
		err = errSpace
	}
	return
}

// ReadAt provides the ReaderAt interface.
func (b *buffer) ReadAt(p []byte, off int64) (n int, err error) {
	if !(b.bottom <= off && off <= b.top) {
		return 0, rangeError{"off", off}
	}
	end := add(off, int64(len(p)))
	if end > b.top {
		end = b.top
	}
	n, err = b.writeRangeTo(off, end, &readAtBuffer{p})
	if err == errSpace {
		err = nil
	}
	return
}

// equalBytes count the equal bytes at off1 and off2 until max is reached.
func (b *buffer) equalBytes(off1, off2 int64, max int) int {
	if off1 < b.bottom || off2 < b.bottom || max <= 0 {
		return 0
	}
	m := int64(max)
	k := b.top - off1
	if k < m {
		if k <= 0 {
			return 0
		}
		m = k
	}
	k = b.top - off2
	if k < m {
		if k <= 0 {
			return 0
		}
		m = k
	}
	for k = 0; k < m; k++ {
		i, j := b.index(off1+k), b.index(off2+k)
		if b.data[i] != b.data[j] {
			break
		}
	}
	return int(k)
}

// resets the buffer to its original values.
func (b *buffer) reset() {
	b.top = 0
	b.bottom = 0
	b.writeLimit = maxLimit
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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.

// The statuscheck package provides an API for reporting status changes from plugins to the statuscheck plugin,
// which exposes them via etcd and HTTP.
//
// The API provides only two functions, one for registering the plugin for status change reporting and one
// for reporting status changes.
//
// To register a plugin for providing status reports, use Register() function:
//	statuscheck.Register(PluginID, probe)
//
// If probe is not nil, statuscheck will periodically probe the plugin state through the provided function.
// Otherwise, it is expected that the plugin itself will report state updates through ReportStateChange():
//	statuscheck.ReportStateChange(PluginID, statuscheck.OK, nil)
//
// The default status of a plugin after registering is Init.
package statuscheck
<commit_msg>Fix golint<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 statuscheck provides an API for reporting status changes from plugins to the statuscheck plugin,
// which exposes them via etcd and HTTP.
//
// The API provides only two functions, one for registering the plugin for status change reporting and one
// for reporting status changes.
//
// To register a plugin for providing status reports, use Register() function:
//	statuscheck.Register(PluginID, probe)
//
// If probe is not nil, statuscheck will periodically probe the plugin state through the provided function.
// Otherwise, it is expected that the plugin itself will report state updates through ReportStateChange():
//	statuscheck.ReportStateChange(PluginID, statuscheck.OK, nil)
//
// The default status of a plugin after registering is Init.
package statuscheck
<|endoftext|>


<commit_before>package rpcd

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/Symantec/Dominator/lib/filesystem"
	"github.com/Symantec/Dominator/lib/fsutil"
	"github.com/Symantec/Dominator/lib/hash"
	"github.com/Symantec/Dominator/lib/objectcache"
	"github.com/Symantec/Dominator/lib/srpc"
	"github.com/Symantec/Dominator/lib/triggers"
	"github.com/Symantec/Dominator/proto/sub"
	"io"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"
	"syscall"
	"time"
)

var (
	readOnly = flag.Bool("readOnly", false,
		"If true, refuse all Fetch and Update requests. For debugging only")
	disableUpdates = flag.Bool("disableUpdates", false,
		"If true, refuse all Update requests. For debugging only")
	disableTriggers = flag.Bool("disableTriggers", false,
		"If true, do not run any triggers. For debugging only")
)

func (t *rpcType) Update(conn *srpc.Conn) {
	var request sub.UpdateRequest
	var response sub.UpdateResponse
	decoder := gob.NewDecoder(conn)
	if err := decoder.Decode(&request); err != nil {
		conn.WriteString(err.Error() + "\n")
		return
	}
	if err := t.update(request, &response); err != nil {
		conn.WriteString(err.Error() + "\n")
		return
	}
	conn.WriteString("\n")
	encoder := gob.NewEncoder(conn)
	encoder.Encode(response)
}

func (t *rpcType) update(request sub.UpdateRequest,
	reply *sub.UpdateResponse) error {
	if *readOnly || *disableUpdates {
		txt := "Update() rejected due to read-only mode"
		t.logger.Println(txt)
		return errors.New(txt)
	}
	t.rwLock.Lock()
	defer t.rwLock.Unlock()
	fs := t.fileSystemHistory.FileSystem()
	if fs == nil {
		return errors.New("No file-system history yet")
	}
	t.logger.Printf("Update()\n")
	if t.fetchInProgress {
		t.logger.Println("Error: fetch already in progress")
		return errors.New("fetch already in progress")
	}
	if t.updateInProgress {
		t.logger.Println("Error: update progress")
		return errors.New("update in progress")
	}
	t.updateInProgress = true
	go t.doUpdate(request, fs.RootDirectoryName())
	return nil
}

func (t *rpcType) doUpdate(request sub.UpdateRequest,
	rootDirectoryName string) {
	defer t.clearUpdateInProgress()
	t.disableScannerFunc(true)
	defer t.disableScannerFunc(false)
	startTime := time.Now()
	var oldTriggers triggers.Triggers
	file, err := os.Open(t.oldTriggersFilename)
	if err == nil {
		decoder := json.NewDecoder(file)
		var trig triggers.Triggers
		err = decoder.Decode(&trig.Triggers)
		file.Close()
		if err == nil {
			oldTriggers = trig
		} else {
			t.logger.Printf("Error decoding old triggers: %s", err.Error())
		}
	}
	t.copyFilesToCache(request.FilesToCopyToCache, rootDirectoryName)
	t.makeObjectCopies(request.MultiplyUsedObjects)
	t.lastUpdateHadTriggerFailures = false
	if len(oldTriggers.Triggers) > 0 {
		t.makeInodes(request.InodesToMake, rootDirectoryName,
			request.MultiplyUsedObjects, &oldTriggers, false)
		makeHardlinks(request.HardlinksToMake, rootDirectoryName,
			&oldTriggers, false, t.logger)
		doDeletes(request.PathsToDelete, rootDirectoryName, &oldTriggers, false,
			t.logger)
		t.makeDirectories(request.DirectoriesToMake, rootDirectoryName,
			&oldTriggers, false)
		changeInodes(request.InodesToChange, rootDirectoryName, &oldTriggers,
			false, t.logger)
		matchedOldTriggers := oldTriggers.GetMatchedTriggers()
		if runTriggers(matchedOldTriggers, "stop", t.logger) {
			t.lastUpdateHadTriggerFailures = true
		}
	}
	t.makeInodes(request.InodesToMake, rootDirectoryName,
		request.MultiplyUsedObjects, request.Triggers, true)
	makeHardlinks(request.HardlinksToMake, rootDirectoryName,
		request.Triggers, true, t.logger)
	doDeletes(request.PathsToDelete, rootDirectoryName, request.Triggers, true,
		t.logger)
	t.makeDirectories(request.DirectoriesToMake, rootDirectoryName,
		request.Triggers, true)
	changeInodes(request.InodesToChange, rootDirectoryName, request.Triggers,
		true, t.logger)
	matchedNewTriggers := request.Triggers.GetMatchedTriggers()
	file, err = os.Create(t.oldTriggersFilename)
	if err == nil {
		b, err := json.Marshal(request.Triggers.Triggers)
		if err == nil {
			var out bytes.Buffer
			json.Indent(&out, b, "", "    ")
			out.WriteTo(file)
		} else {
			t.logger.Printf("Error marshaling triggers: %s", err.Error())
		}
		file.Close()
	}
	if runTriggers(matchedNewTriggers, "start", t.logger) {
		t.lastUpdateHadTriggerFailures = true
	}
	timeTaken := time.Since(startTime)
	t.logger.Printf("Update() completed in %s\n", timeTaken)
}

func (t *rpcType) clearUpdateInProgress() {
	t.rwLock.Lock()
	defer t.rwLock.Unlock()
	t.updateInProgress = false
}

func (t *rpcType) copyFilesToCache(filesToCopyToCache []sub.FileToCopyToCache,
	rootDirectoryName string) {
	for _, fileToCopy := range filesToCopyToCache {
		sourcePathname := path.Join(rootDirectoryName, fileToCopy.Name)
		destPathname := path.Join(t.objectsDir,
			objectcache.HashToFilename(fileToCopy.Hash))
		if err := copyFile(destPathname, sourcePathname); err != nil {
			t.logger.Println(err)
		} else {
			t.logger.Printf("Copied: %s to cache\n", sourcePathname)
		}
	}
}

func copyFile(destPathname, sourcePathname string) error {
	sourceFile, err := os.Open(sourcePathname)
	if err != nil {
		return err
	}
	defer sourceFile.Close()
	dirname := path.Dir(destPathname)
	if err := os.MkdirAll(dirname, syscall.S_IRWXU); err != nil {
		return err
	}
	destFile, err := os.Create(destPathname)
	if err != nil {
		return err
	}
	defer destFile.Close()
	_, err = io.Copy(destFile, sourceFile)
	return err
}

func (t *rpcType) makeObjectCopies(multiplyUsedObjects map[hash.Hash]uint64) {
	for hash, numCopies := range multiplyUsedObjects {
		if numCopies < 2 {
			continue
		}
		objectPathname := path.Join(t.objectsDir,
			objectcache.HashToFilename(hash))
		for numCopies--; numCopies > 0; numCopies-- {
			ext := strings.Repeat("~", int(numCopies))
			if err := copyFile(objectPathname+ext, objectPathname); err != nil {
				t.logger.Println(err)
			} else {
				t.logger.Printf("Copied object: %x%s\n", hash, ext)
			}
		}
	}
}

func (t *rpcType) makeInodes(inodesToMake []sub.Inode, rootDirectoryName string,
	multiplyUsedObjects map[hash.Hash]uint64, triggers *triggers.Triggers,
	takeAction bool) {
	for _, inode := range inodesToMake {
		fullPathname := path.Join(rootDirectoryName, inode.Name)
		triggers.Match(inode.Name)
		if takeAction {
			switch inode := inode.GenericInode.(type) {
			case *filesystem.RegularInode:
				makeRegularInode(fullPathname, inode, multiplyUsedObjects,
					t.objectsDir, t.logger)
			case *filesystem.SymlinkInode:
				makeSymlinkInode(fullPathname, inode, t.logger)
			case *filesystem.SpecialInode:
				makeSpecialInode(fullPathname, inode, t.logger)
			}
		}
	}
}

func makeRegularInode(fullPathname string,
	inode *filesystem.RegularInode, multiplyUsedObjects map[hash.Hash]uint64,
	objectsDir string, logger *log.Logger) {
	var err error
	if inode.Size > 0 {
		objectPathname := path.Join(objectsDir,
			objectcache.HashToFilename(inode.Hash))
		numCopies := multiplyUsedObjects[inode.Hash]
		if numCopies > 1 {
			numCopies--
			objectPathname += strings.Repeat("~", int(numCopies))
			if numCopies < 2 {
				delete(multiplyUsedObjects, inode.Hash)
			} else {
				multiplyUsedObjects[inode.Hash] = numCopies
			}
		}
		err = fsutil.ForceRename(objectPathname, fullPathname)
	} else {
		_, err = os.Create(fullPathname)
	}
	if err != nil {
		logger.Println(err)
		return
	}
	if err := inode.WriteMetadata(fullPathname); err != nil {
		logger.Println(err)
	} else {
		if inode.Size > 0 {
			logger.Printf("Made inode: %s from: %x\n",
				fullPathname, inode.Hash)
		} else {
			logger.Printf("Made empty inode: %s\n", fullPathname)
		}
	}
}

func makeSymlinkInode(fullPathname string,
	inode *filesystem.SymlinkInode, logger *log.Logger) {
	if err := inode.Write(fullPathname); err != nil {
		logger.Println(err)
	} else {
		logger.Printf("Made symlink inode: %s -> %s\n",
			fullPathname, inode.Symlink)
	}
}

func makeSpecialInode(fullPathname string, inode *filesystem.SpecialInode,
	logger *log.Logger) {
	if err := inode.Write(fullPathname); err != nil {
		logger.Println(err)
	} else {
		logger.Printf("Made special inode: %s\n", fullPathname)
	}
}

func makeHardlinks(hardlinksToMake []sub.Hardlink, rootDirectoryName string,
	triggers *triggers.Triggers, takeAction bool, logger *log.Logger) {
	for _, hardlink := range hardlinksToMake {
		triggers.Match(hardlink.NewLink)
		if takeAction {
			targetPathname := path.Join(rootDirectoryName, hardlink.Target)
			linkPathname := path.Join(rootDirectoryName, hardlink.NewLink)
			if err := fsutil.ForceLink(targetPathname,
				linkPathname); err != nil {
				logger.Println(err)
			} else {
				logger.Printf("Linked: %s => %s\n",
					linkPathname, targetPathname)
			}
		}
	}
}

func doDeletes(pathsToDelete []string, rootDirectoryName string,
	triggers *triggers.Triggers, takeAction bool, logger *log.Logger) {
	for _, pathname := range pathsToDelete {
		fullPathname := path.Join(rootDirectoryName, pathname)
		triggers.Match(pathname)
		if takeAction {
			if err := fsutil.ForceRemoveAll(fullPathname); err != nil {
				logger.Println(err)
			} else {
				logger.Printf("Deleted: %s\n", fullPathname)
			}
		}
	}
}

func (t *rpcType) makeDirectories(directoriesToMake []sub.Inode,
	rootDirectoryName string, triggers *triggers.Triggers, takeAction bool) {
	for _, newdir := range directoriesToMake {
		if t.skipPath(newdir.Name) {
			continue
		}
		fullPathname := path.Join(rootDirectoryName, newdir.Name)
		triggers.Match(newdir.Name)
		if takeAction {
			inode, ok := newdir.GenericInode.(*filesystem.DirectoryInode)
			if !ok {
				t.logger.Println("%s is not a directory!\n", newdir.Name)
				continue
			}
			if err := inode.Write(fullPathname); err != nil {
				t.logger.Println(err)
			} else {
				t.logger.Printf("Made directory: %s\n", fullPathname)
			}
		}
	}
}

func changeInodes(inodesToChange []sub.Inode, rootDirectoryName string,
	triggers *triggers.Triggers, takeAction bool, logger *log.Logger) {
	for _, inode := range inodesToChange {
		fullPathname := path.Join(rootDirectoryName, inode.Name)
		triggers.Match(inode.Name)
		if takeAction {
			if err := filesystem.ForceWriteMetadata(inode,
				fullPathname); err != nil {
				logger.Println(err)
				continue
			}
			logger.Printf("Changed inode: %s\n", fullPathname)
		}
	}
}

func (t *rpcType) skipPath(pathname string) bool {
	if t.scannerConfiguration.ScanFilter.Match(pathname) {
		return true
	}
	if pathname == "/.subd" {
		return true
	}
	if strings.HasPrefix(pathname, "/.subd/") {
		return true
	}
	return false
}

func runTriggers(triggers []*triggers.Trigger, action string,
	logger *log.Logger) bool {
	hadFailures := false
	logPrefix := ""
	if *disableTriggers {
		logPrefix = "Disabled: "
	}
	// For "start" action, if there is a reboot trigger, just do that one.
	if action == "start" {
		for _, trigger := range triggers {
			if trigger.Service == "reboot" {
				logger.Print(logPrefix, "Rebooting")
				if *disableTriggers {
					return hadFailures
				}
				cmd := exec.Command("reboot")
				cmd.Stdout = os.Stdout
				if err := cmd.Run(); err != nil {
					hadFailures = true
					logger.Print(err)
				}
				return hadFailures
			}
		}
	}
	ppid := fmt.Sprint(os.Getppid())
	for _, trigger := range triggers {
		if trigger.Service == "reboot" && action == "stop" {
			continue
		}
		logger.Printf("%sAction: service %s %s\n",
			logPrefix, trigger.Service, action)
		if *disableTriggers {
			continue
		}
		cmd := exec.Command("run-in-mntns", ppid, "service", action,
			trigger.Service)
		cmd.Stdout = os.Stdout
		if err := cmd.Run(); err != nil {
			hadFailures = true
			logger.Print(err)
		}
	}
	return hadFailures
}
<commit_msg> Fix bug in Subd.Update(): replace existing file when hardlinking.<commit_after>package rpcd

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/Symantec/Dominator/lib/filesystem"
	"github.com/Symantec/Dominator/lib/fsutil"
	"github.com/Symantec/Dominator/lib/hash"
	"github.com/Symantec/Dominator/lib/objectcache"
	"github.com/Symantec/Dominator/lib/srpc"
	"github.com/Symantec/Dominator/lib/triggers"
	"github.com/Symantec/Dominator/proto/sub"
	"io"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"
	"syscall"
	"time"
)

var (
	readOnly = flag.Bool("readOnly", false,
		"If true, refuse all Fetch and Update requests. For debugging only")
	disableUpdates = flag.Bool("disableUpdates", false,
		"If true, refuse all Update requests. For debugging only")
	disableTriggers = flag.Bool("disableTriggers", false,
		"If true, do not run any triggers. For debugging only")
)

func (t *rpcType) Update(conn *srpc.Conn) {
	var request sub.UpdateRequest
	var response sub.UpdateResponse
	decoder := gob.NewDecoder(conn)
	if err := decoder.Decode(&request); err != nil {
		conn.WriteString(err.Error() + "\n")
		return
	}
	if err := t.update(request, &response); err != nil {
		conn.WriteString(err.Error() + "\n")
		return
	}
	conn.WriteString("\n")
	encoder := gob.NewEncoder(conn)
	encoder.Encode(response)
}

func (t *rpcType) update(request sub.UpdateRequest,
	reply *sub.UpdateResponse) error {
	if *readOnly || *disableUpdates {
		txt := "Update() rejected due to read-only mode"
		t.logger.Println(txt)
		return errors.New(txt)
	}
	t.rwLock.Lock()
	defer t.rwLock.Unlock()
	fs := t.fileSystemHistory.FileSystem()
	if fs == nil {
		return errors.New("No file-system history yet")
	}
	t.logger.Printf("Update()\n")
	if t.fetchInProgress {
		t.logger.Println("Error: fetch already in progress")
		return errors.New("fetch already in progress")
	}
	if t.updateInProgress {
		t.logger.Println("Error: update progress")
		return errors.New("update in progress")
	}
	t.updateInProgress = true
	go t.doUpdate(request, fs.RootDirectoryName())
	return nil
}

func (t *rpcType) doUpdate(request sub.UpdateRequest,
	rootDirectoryName string) {
	defer t.clearUpdateInProgress()
	t.disableScannerFunc(true)
	defer t.disableScannerFunc(false)
	startTime := time.Now()
	var oldTriggers triggers.Triggers
	file, err := os.Open(t.oldTriggersFilename)
	if err == nil {
		decoder := json.NewDecoder(file)
		var trig triggers.Triggers
		err = decoder.Decode(&trig.Triggers)
		file.Close()
		if err == nil {
			oldTriggers = trig
		} else {
			t.logger.Printf("Error decoding old triggers: %s", err.Error())
		}
	}
	t.copyFilesToCache(request.FilesToCopyToCache, rootDirectoryName)
	t.makeObjectCopies(request.MultiplyUsedObjects)
	t.lastUpdateHadTriggerFailures = false
	if len(oldTriggers.Triggers) > 0 {
		t.makeInodes(request.InodesToMake, rootDirectoryName,
			request.MultiplyUsedObjects, &oldTriggers, false)
		makeHardlinks(request.HardlinksToMake, rootDirectoryName,
			&oldTriggers, "", false, t.logger)
		doDeletes(request.PathsToDelete, rootDirectoryName, &oldTriggers, false,
			t.logger)
		t.makeDirectories(request.DirectoriesToMake, rootDirectoryName,
			&oldTriggers, false)
		changeInodes(request.InodesToChange, rootDirectoryName, &oldTriggers,
			false, t.logger)
		matchedOldTriggers := oldTriggers.GetMatchedTriggers()
		if runTriggers(matchedOldTriggers, "stop", t.logger) {
			t.lastUpdateHadTriggerFailures = true
		}
	}
	t.makeInodes(request.InodesToMake, rootDirectoryName,
		request.MultiplyUsedObjects, request.Triggers, true)
	makeHardlinks(request.HardlinksToMake, rootDirectoryName,
		request.Triggers, t.objectsDir, true, t.logger)
	doDeletes(request.PathsToDelete, rootDirectoryName, request.Triggers, true,
		t.logger)
	t.makeDirectories(request.DirectoriesToMake, rootDirectoryName,
		request.Triggers, true)
	changeInodes(request.InodesToChange, rootDirectoryName, request.Triggers,
		true, t.logger)
	matchedNewTriggers := request.Triggers.GetMatchedTriggers()
	file, err = os.Create(t.oldTriggersFilename)
	if err == nil {
		b, err := json.Marshal(request.Triggers.Triggers)
		if err == nil {
			var out bytes.Buffer
			json.Indent(&out, b, "", "    ")
			out.WriteTo(file)
		} else {
			t.logger.Printf("Error marshaling triggers: %s", err.Error())
		}
		file.Close()
	}
	if runTriggers(matchedNewTriggers, "start", t.logger) {
		t.lastUpdateHadTriggerFailures = true
	}
	timeTaken := time.Since(startTime)
	t.logger.Printf("Update() completed in %s\n", timeTaken)
}

func (t *rpcType) clearUpdateInProgress() {
	t.rwLock.Lock()
	defer t.rwLock.Unlock()
	t.updateInProgress = false
}

func (t *rpcType) copyFilesToCache(filesToCopyToCache []sub.FileToCopyToCache,
	rootDirectoryName string) {
	for _, fileToCopy := range filesToCopyToCache {
		sourcePathname := path.Join(rootDirectoryName, fileToCopy.Name)
		destPathname := path.Join(t.objectsDir,
			objectcache.HashToFilename(fileToCopy.Hash))
		if err := copyFile(destPathname, sourcePathname); err != nil {
			t.logger.Println(err)
		} else {
			t.logger.Printf("Copied: %s to cache\n", sourcePathname)
		}
	}
}

func copyFile(destPathname, sourcePathname string) error {
	sourceFile, err := os.Open(sourcePathname)
	if err != nil {
		return err
	}
	defer sourceFile.Close()
	dirname := path.Dir(destPathname)
	if err := os.MkdirAll(dirname, syscall.S_IRWXU); err != nil {
		return err
	}
	destFile, err := os.Create(destPathname)
	if err != nil {
		return err
	}
	defer destFile.Close()
	_, err = io.Copy(destFile, sourceFile)
	return err
}

func (t *rpcType) makeObjectCopies(multiplyUsedObjects map[hash.Hash]uint64) {
	for hash, numCopies := range multiplyUsedObjects {
		if numCopies < 2 {
			continue
		}
		objectPathname := path.Join(t.objectsDir,
			objectcache.HashToFilename(hash))
		for numCopies--; numCopies > 0; numCopies-- {
			ext := strings.Repeat("~", int(numCopies))
			if err := copyFile(objectPathname+ext, objectPathname); err != nil {
				t.logger.Println(err)
			} else {
				t.logger.Printf("Copied object: %x%s\n", hash, ext)
			}
		}
	}
}

func (t *rpcType) makeInodes(inodesToMake []sub.Inode, rootDirectoryName string,
	multiplyUsedObjects map[hash.Hash]uint64, triggers *triggers.Triggers,
	takeAction bool) {
	for _, inode := range inodesToMake {
		fullPathname := path.Join(rootDirectoryName, inode.Name)
		triggers.Match(inode.Name)
		if takeAction {
			switch inode := inode.GenericInode.(type) {
			case *filesystem.RegularInode:
				makeRegularInode(fullPathname, inode, multiplyUsedObjects,
					t.objectsDir, t.logger)
			case *filesystem.SymlinkInode:
				makeSymlinkInode(fullPathname, inode, t.logger)
			case *filesystem.SpecialInode:
				makeSpecialInode(fullPathname, inode, t.logger)
			}
		}
	}
}

func makeRegularInode(fullPathname string,
	inode *filesystem.RegularInode, multiplyUsedObjects map[hash.Hash]uint64,
	objectsDir string, logger *log.Logger) {
	var err error
	if inode.Size > 0 {
		objectPathname := path.Join(objectsDir,
			objectcache.HashToFilename(inode.Hash))
		numCopies := multiplyUsedObjects[inode.Hash]
		if numCopies > 1 {
			numCopies--
			objectPathname += strings.Repeat("~", int(numCopies))
			if numCopies < 2 {
				delete(multiplyUsedObjects, inode.Hash)
			} else {
				multiplyUsedObjects[inode.Hash] = numCopies
			}
		}
		err = fsutil.ForceRename(objectPathname, fullPathname)
	} else {
		_, err = os.Create(fullPathname)
	}
	if err != nil {
		logger.Println(err)
		return
	}
	if err := inode.WriteMetadata(fullPathname); err != nil {
		logger.Println(err)
	} else {
		if inode.Size > 0 {
			logger.Printf("Made inode: %s from: %x\n",
				fullPathname, inode.Hash)
		} else {
			logger.Printf("Made empty inode: %s\n", fullPathname)
		}
	}
}

func makeSymlinkInode(fullPathname string,
	inode *filesystem.SymlinkInode, logger *log.Logger) {
	if err := inode.Write(fullPathname); err != nil {
		logger.Println(err)
	} else {
		logger.Printf("Made symlink inode: %s -> %s\n",
			fullPathname, inode.Symlink)
	}
}

func makeSpecialInode(fullPathname string, inode *filesystem.SpecialInode,
	logger *log.Logger) {
	if err := inode.Write(fullPathname); err != nil {
		logger.Println(err)
	} else {
		logger.Printf("Made special inode: %s\n", fullPathname)
	}
}

func makeHardlinks(hardlinksToMake []sub.Hardlink, rootDirectoryName string,
	triggers *triggers.Triggers, tmpDir string, takeAction bool,
	logger *log.Logger) {
	tmpName := path.Join(tmpDir, "temporaryHardlink")
	for _, hardlink := range hardlinksToMake {
		triggers.Match(hardlink.NewLink)
		if takeAction {
			targetPathname := path.Join(rootDirectoryName, hardlink.Target)
			linkPathname := path.Join(rootDirectoryName, hardlink.NewLink)
			// A Link directly to linkPathname will fail if it exists, so do a
			// Link+Rename using a temporary filename.
			if err := fsutil.ForceLink(targetPathname, tmpName); err != nil {
				logger.Println(err)
				continue
			}
			if err := fsutil.ForceRename(tmpName, linkPathname); err != nil {
				logger.Println(err)
				if err := fsutil.ForceRemove(tmpName); err != nil {
					logger.Println(err)
				}
			} else {
				logger.Printf("Linked: %s => %s\n",
					linkPathname, targetPathname)
			}
		}
	}
}

func doDeletes(pathsToDelete []string, rootDirectoryName string,
	triggers *triggers.Triggers, takeAction bool, logger *log.Logger) {
	for _, pathname := range pathsToDelete {
		fullPathname := path.Join(rootDirectoryName, pathname)
		triggers.Match(pathname)
		if takeAction {
			if err := fsutil.ForceRemoveAll(fullPathname); err != nil {
				logger.Println(err)
			} else {
				logger.Printf("Deleted: %s\n", fullPathname)
			}
		}
	}
}

func (t *rpcType) makeDirectories(directoriesToMake []sub.Inode,
	rootDirectoryName string, triggers *triggers.Triggers, takeAction bool) {
	for _, newdir := range directoriesToMake {
		if t.skipPath(newdir.Name) {
			continue
		}
		fullPathname := path.Join(rootDirectoryName, newdir.Name)
		triggers.Match(newdir.Name)
		if takeAction {
			inode, ok := newdir.GenericInode.(*filesystem.DirectoryInode)
			if !ok {
				t.logger.Println("%s is not a directory!\n", newdir.Name)
				continue
			}
			if err := inode.Write(fullPathname); err != nil {
				t.logger.Println(err)
			} else {
				t.logger.Printf("Made directory: %s\n", fullPathname)
			}
		}
	}
}

func changeInodes(inodesToChange []sub.Inode, rootDirectoryName string,
	triggers *triggers.Triggers, takeAction bool, logger *log.Logger) {
	for _, inode := range inodesToChange {
		fullPathname := path.Join(rootDirectoryName, inode.Name)
		triggers.Match(inode.Name)
		if takeAction {
			if err := filesystem.ForceWriteMetadata(inode,
				fullPathname); err != nil {
				logger.Println(err)
				continue
			}
			logger.Printf("Changed inode: %s\n", fullPathname)
		}
	}
}

func (t *rpcType) skipPath(pathname string) bool {
	if t.scannerConfiguration.ScanFilter.Match(pathname) {
		return true
	}
	if pathname == "/.subd" {
		return true
	}
	if strings.HasPrefix(pathname, "/.subd/") {
		return true
	}
	return false
}

func runTriggers(triggers []*triggers.Trigger, action string,
	logger *log.Logger) bool {
	hadFailures := false
	logPrefix := ""
	if *disableTriggers {
		logPrefix = "Disabled: "
	}
	// For "start" action, if there is a reboot trigger, just do that one.
	if action == "start" {
		for _, trigger := range triggers {
			if trigger.Service == "reboot" {
				logger.Print(logPrefix, "Rebooting")
				if *disableTriggers {
					return hadFailures
				}
				cmd := exec.Command("reboot")
				cmd.Stdout = os.Stdout
				if err := cmd.Run(); err != nil {
					hadFailures = true
					logger.Print(err)
				}
				return hadFailures
			}
		}
	}
	ppid := fmt.Sprint(os.Getppid())
	for _, trigger := range triggers {
		if trigger.Service == "reboot" && action == "stop" {
			continue
		}
		logger.Printf("%sAction: service %s %s\n",
			logPrefix, trigger.Service, action)
		if *disableTriggers {
			continue
		}
		cmd := exec.Command("run-in-mntns", ppid, "service", action,
			trigger.Service)
		cmd.Stdout = os.Stdout
		if err := cmd.Run(); err != nil {
			hadFailures = true
			logger.Print(err)
		}
	}
	return hadFailures
}
<|endoftext|>


<commit_before>package tabs

import (
	"github.com/MJKWoolnough/gopherjs/style"
	"github.com/MJKWoolnough/gopherjs/xjs"
	"honnef.co/go/js/dom"
)

const css = `.tabs {
	line-height : 24px;
	position : relative;
	width : 100%;
	overflow : hidden;
	margin : 0;
	padding : 0 0 0 20px;
	z-index : 0;
}

.tabs:after {
	position : absolute;
	content : "";
	width : 100%;
	bottom : 0;
	left : 0;
	border-bottom: 1px solid #000;
	z-index : 1;
	overflow : hidden;
	text-align : center;
	transform : translateX(-20px);
}

.tabs > div {
	border : 1px solid #000;
	display : inline-block;
	position : relative;
	z-index : 1;
	margin : 0 -5px;
	padding : 0 20px;
	border-top-right-radius: 6px;
	border-top-left-radius: 6px;
	background : linear-gradient(to bottom, #ececec 50%, #d1d1d1 100%);
	box-shadow : 0 3px 3px rgba(0, 0, 0, 0.4), inset 0 1px 0 #fff;
	text-shadow : 0 1px #fff;
	user-select : none;
	-moz-user-select : none;
	-webkit-user-select : none;
}

.tabs > div:hover {
	background : linear-gradient(to bottom, #faa 1%, #ffecec 50%, #d1d1d1 100%);
	cursor : pointer;
}

.tabs > div:before, .tabs > div:after {
	position : absolute;
	bottom : -1px;
	width : 6px;
	height : 6px;
	content : " ";
	border : 1px solid #000;
}

.tabs > div:before {
	left : -7px;
	border-bottom-right-radius : 6px;
	border-width : 0 1px 1px 0;
	box-shadow: 2px 2px 0 #d1d1d1;
}

.tabs > div:after {
	right : -7px;
	border-bottom-left-radius : 6px;
	border-width : 0 0 1px 1px;
	box-shadow: -2px 2px 0 #d1d1d1;
}

.tabs > div.selected {
	border-bottom-color : #fff;
	z-index : 2;
	background : #fff;
}

.tabs > div.selected:hover {
	background : #fff;
	cursor : default;
}

.tabs > div.selected:before {
	box-shadow: 2px 2px 0 #fff;
}

.tabs > div.selected:after {
	box-shadow: -2px 2px 0 #fff;
}

.tabs + .content {
	margin-top : 10px;
	padding : 10px;
}`

func init() {
	style.Add(css)
}

type Tab struct {
	Name string
	Func func(dom.Element)
}

func MakeTabs(t []Tab) dom.Node {
	f := xjs.DocumentFragment()
	if len(t) < 0 {
		return f
	}
	tabsDiv := xjs.CreateElement("div")
	contents := xjs.CreateElement("div")
	tabsDiv.Class().SetString("tabs")
	contents.Class().SetString("content")
	tabs := make([]dom.Element, len(t))
	for n := range t {
		tabs[n] = xjs.SetInnerText(xjs.CreateElement("div"), t[n].Name).(dom.Element)
		tabs[n].AddEventListener("click", false, func() func(dom.Event) {
			i := n
			return func(e dom.Event) {
				if tabs[i].Class().String() == "selected" {
					return
				}
				for _, tab := range tabs {
					tab.Class().Remove("selected")
				}
				newContents := contents.CloneNode(false).(dom.Element)
				contents.ParentNode().ReplaceChild(newContents, contents)
				contents = newContents
				tabs[i].Class().Add("selected")
				go t[i].Func(contents)
			}
		}())
		tabsDiv.AppendChild(tabs[n])
	}
	t[0].Func(contents)
	tabs[0].Class().Add("selected")
	f.AppendChild(tabsDiv)
	f.AppendChild(contents)
	return f
}
<commit_msg>Updated style<commit_after>package tabs

import (
	"github.com/MJKWoolnough/gopherjs/style"
	"github.com/MJKWoolnough/gopherjs/xjs"
	"honnef.co/go/js/dom"
)

const css = `.tabs {
	line-height : 24px;
	position : relative;
	width : 100%;
	overflow : hidden;
	margin : 0;
	padding : 0 0 0 20px;
	z-index : 0;
}

.tabs:after {
	position : absolute;
	content : "";
	width : 100%;
	bottom : 0;
	left : 0;
	border-bottom: 1px solid #000;
	z-index : 1;
	overflow : hidden;
	text-align : center;
	transform : translateX(-20px);
}

.tabs > div {
	border : 1px solid #000;
	display : inline-block;
	position : relative;
	z-index : 1;
	margin : 0 -5px;
	padding : 0 20px;
	border-top-right-radius: 6px;
	border-top-left-radius: 6px;
	background : linear-gradient(to bottom, #ececec 50%, #d1d1d1 100%);
	box-shadow : 0 3px 3px rgba(0, 0, 0, 0.4), inset 0 1px 0 #fff;
	text-shadow : 0 1px #fff;
	user-select : none;
	-moz-user-select : none;
	-webkit-user-select : none;
}

.tabs > div:hover {
	background : linear-gradient(to bottom, #faa 1%, #ffecec 50%, #d1d1d1 100%);
	cursor : pointer;
}

.tabs > div:before, .tabs > div:after {
	position : absolute;
	bottom : -1px;
	width : 6px;
	height : 6px;
	content : " ";
	border : 1px solid #000;
}

.tabs > div:before {
	left : -7px;
	border-bottom-right-radius : 6px;
	border-width : 0 1px 1px 0;
	box-shadow: 2px 2px 0 #d1d1d1;
}

.tabs > div:after {
	right : -7px;
	border-bottom-left-radius : 6px;
	border-width : 0 0 1px 1px;
	box-shadow: -2px 2px 0 #d1d1d1;
}

.tabs > div.selected {
	border-bottom-color : #fff;
	z-index : 2;
	background : #fff;
}

.tabs > div.selected:hover {
	background : #fff;
	cursor : default;
}

.tabs > div.selected:before {
	box-shadow: 2px 2px 0 #fff;
}

.tabs > div.selected:after {
	box-shadow: -2px 2px 0 #fff;
}

.tabs + .content {
	margin-top : 10px;
	padding : 10px 0 0 0;
}`

func init() {
	style.Add(css)
}

type Tab struct {
	Name string
	Func func(dom.Element)
}

func MakeTabs(t []Tab) dom.Node {
	f := xjs.DocumentFragment()
	if len(t) < 0 {
		return f
	}
	tabsDiv := xjs.CreateElement("div")
	contents := xjs.CreateElement("div")
	tabsDiv.Class().SetString("tabs")
	contents.Class().SetString("content")
	tabs := make([]dom.Element, len(t))
	for n := range t {
		tabs[n] = xjs.SetInnerText(xjs.CreateElement("div"), t[n].Name).(dom.Element)
		tabs[n].AddEventListener("click", false, func() func(dom.Event) {
			i := n
			return func(e dom.Event) {
				if tabs[i].Class().String() == "selected" {
					return
				}
				for _, tab := range tabs {
					tab.Class().Remove("selected")
				}
				newContents := contents.CloneNode(false).(dom.Element)
				contents.ParentNode().ReplaceChild(newContents, contents)
				contents = newContents
				tabs[i].Class().Add("selected")
				go t[i].Func(contents)
			}
		}())
		tabsDiv.AppendChild(tabs[n])
	}
	t[0].Func(contents)
	tabs[0].Class().Add("selected")
	f.AppendChild(tabsDiv)
	f.AppendChild(contents)
	return f
}
<|endoftext|>


<commit_before>// generated by go-import-subtree -- DO NOT EDIT
package main

import _ "github.com/taskcluster/taskcluster-worker/engines/enginetest"
import _ "github.com/taskcluster/taskcluster-worker/engines/mock"
import _ "github.com/taskcluster/taskcluster-worker/engines/osxnative"
import _ "github.com/taskcluster/taskcluster-worker/engines/qemu"
import _ "github.com/taskcluster/taskcluster-worker/plugins/artifacts"
import _ "github.com/taskcluster/taskcluster-worker/plugins/env"
import _ "github.com/taskcluster/taskcluster-worker/plugins/livelog"
import _ "github.com/taskcluster/taskcluster-worker/plugins/interactive"
import _ "github.com/taskcluster/taskcluster-worker/plugins/plugintest"
import _ "github.com/taskcluster/taskcluster-worker/plugins/success"
import _ "github.com/taskcluster/taskcluster-worker/commands/daemon"
import _ "github.com/taskcluster/taskcluster-worker/commands/help"
import _ "github.com/taskcluster/taskcluster-worker/commands/qemu-build"
import _ "github.com/taskcluster/taskcluster-worker/commands/qemu-guest-tools"
import _ "github.com/taskcluster/taskcluster-worker/commands/qemu-run"
import _ "github.com/taskcluster/taskcluster-worker/commands/schema"
import _ "github.com/taskcluster/taskcluster-worker/commands/shell"
import _ "github.com/taskcluster/taskcluster-worker/commands/work"
<commit_msg>make generate to ensure consistent go fmt result<commit_after>// generated by go-import-subtree -- DO NOT EDIT
package main

import _ "github.com/taskcluster/taskcluster-worker/engines/enginetest"
import _ "github.com/taskcluster/taskcluster-worker/engines/mock"
import _ "github.com/taskcluster/taskcluster-worker/engines/osxnative"
import _ "github.com/taskcluster/taskcluster-worker/engines/qemu"
import _ "github.com/taskcluster/taskcluster-worker/plugins/artifacts"
import _ "github.com/taskcluster/taskcluster-worker/plugins/env"
import _ "github.com/taskcluster/taskcluster-worker/plugins/interactive"
import _ "github.com/taskcluster/taskcluster-worker/plugins/livelog"
import _ "github.com/taskcluster/taskcluster-worker/plugins/plugintest"
import _ "github.com/taskcluster/taskcluster-worker/plugins/success"
import _ "github.com/taskcluster/taskcluster-worker/commands/daemon"
import _ "github.com/taskcluster/taskcluster-worker/commands/help"
import _ "github.com/taskcluster/taskcluster-worker/commands/qemu-build"
import _ "github.com/taskcluster/taskcluster-worker/commands/qemu-guest-tools"
import _ "github.com/taskcluster/taskcluster-worker/commands/qemu-run"
import _ "github.com/taskcluster/taskcluster-worker/commands/schema"
import _ "github.com/taskcluster/taskcluster-worker/commands/shell"
import _ "github.com/taskcluster/taskcluster-worker/commands/work"
<|endoftext|>


<commit_before>package pinba

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestTagsToSortedString(t *testing.T) {
	tags := Tags{Tag{"aaa", "val1"}, Tag{"bbb", "val2"}, Tag{"ccc", "val3"}}
	assert.Equal(t, "aaa=val1 bbb=val2 ccc=val3", tags.String())

	tags = Tags{Tag{"bbb", "val2"}, Tag{"aaa", "val1"}, Tag{"ccc", "val3"}}
	assert.Equal(t, "aaa=val1 bbb=val2 ccc=val3", tags.String())
}

func TestTagsGetTag(t *testing.T) {
	tags := Tags{Tag{"aaa", "val1"}, Tag{"bbb", "val2"}, Tag{"ccc", "val3"}}
	val, err := tags.Get("aaa")
	assert.Nil(t, err)
	assert.Equal(t, "val1", val)

	_, err = tags.Get("xxx")
	assert.NotNil(t, err)
}

func TestTagsFilter(t *testing.T) {
	tags := Tags{Tag{"aaa", "val1"}, Tag{"bbb", "val2"}, Tag{"ccc", "val3"}}
	assert.Equal(t, "aaa=val1 bbb=val2", tags.Filter([]string{"aaa", "bbb"}).String())

	tags = Tags{Tag{"bbb", "val2"}, Tag{"aaa", "val1"}, Tag{"ccc", "val3"}}
	assert.Equal(t, "aaa=val1 bbb=val2", tags.Filter([]string{"aaa", "bbb"}).String())

	tags = Tags{Tag{"bbb", "val2"}, Tag{"aaa", ""}, Tag{"ccc", "val3"}}
	assert.Equal(t, "bbb=val2", tags.Filter([]string{"aaa", "bbb"}).String())
}

func TestTagsStringf(t *testing.T) {
	tags := Tags{Tag{"aaa", "val1"}, Tag{"bbb", "val2"}, Tag{"ccc", "val3"}}

	assert.Equal(t,
		"val1.requests.val2.script",
		tags.Stringf("{aaa}.requests.{bbb}.script"))

	assert.Equal(t,
		"val1.requests.val2.script.{xxx}",
		tags.Stringf("{aaa}.requests.{bbb}.script.{xxx}"))
}

func BenchmarkFilter(b *testing.B) {
	b.ResetTimer()

	tags := Tags{
		Tag{"key1", "val1"},
		Tag{"key2", ""},
		Tag{"key3", "val3"},
		Tag{"key4", "val4"},
		Tag{"key5", "val5"},
		Tag{"key6", ""},
		Tag{"key7", ""},
		Tag{"key8", "val8"},
		Tag{"key9", "val9"},
		Tag{"key10", "val10"},
	}

	filter := []string{"key1", "key3", "key5", "key6", "key9", "key10"}

	for i := 0; i < b.N; i++ {
		tags.Filter(filter)
	}
}

func BenchmarkStringf(b *testing.B) {
	b.ResetTimer()

	tags := Tags{Tag{"aaa", "val1"}, Tag{"bbb", "val2"}, Tag{"ccc", "val3"}}
	for i := 0; i < b.N; i++ {
		tags.Stringf("{aaa}.requests.{bbb}.script")
	}
}
<commit_msg>Add String benchmark<commit_after>package pinba

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestTagsToSortedString(t *testing.T) {
	tags := Tags{Tag{"aaa", "val1"}, Tag{"bbb", "val2"}, Tag{"ccc", "val3"}}
	assert.Equal(t, "aaa=val1 bbb=val2 ccc=val3", tags.String())

	tags = Tags{Tag{"bbb", "val2"}, Tag{"aaa", "val1"}, Tag{"ccc", "val3"}}
	assert.Equal(t, "aaa=val1 bbb=val2 ccc=val3", tags.String())
}

func TestTagsGetTag(t *testing.T) {
	tags := Tags{Tag{"aaa", "val1"}, Tag{"bbb", "val2"}, Tag{"ccc", "val3"}}
	val, err := tags.Get("aaa")
	assert.Nil(t, err)
	assert.Equal(t, "val1", val)

	_, err = tags.Get("xxx")
	assert.NotNil(t, err)
}

func TestTagsFilter(t *testing.T) {
	tags := Tags{Tag{"aaa", "val1"}, Tag{"bbb", "val2"}, Tag{"ccc", "val3"}}
	assert.Equal(t, "aaa=val1 bbb=val2", tags.Filter([]string{"aaa", "bbb"}).String())

	tags = Tags{Tag{"bbb", "val2"}, Tag{"aaa", "val1"}, Tag{"ccc", "val3"}}
	assert.Equal(t, "aaa=val1 bbb=val2", tags.Filter([]string{"aaa", "bbb"}).String())

	tags = Tags{Tag{"bbb", "val2"}, Tag{"aaa", ""}, Tag{"ccc", "val3"}}
	assert.Equal(t, "bbb=val2", tags.Filter([]string{"aaa", "bbb"}).String())
}

func TestTagsStringf(t *testing.T) {
	tags := Tags{Tag{"aaa", "val1"}, Tag{"bbb", "val2"}, Tag{"ccc", "val3"}}

	assert.Equal(t,
		"val1.requests.val2.script",
		tags.Stringf("{aaa}.requests.{bbb}.script"))

	assert.Equal(t,
		"val1.requests.val2.script.{xxx}",
		tags.Stringf("{aaa}.requests.{bbb}.script.{xxx}"))
}

func BenchmarkFilter(b *testing.B) {
	b.ResetTimer()

	tags := Tags{
		Tag{"key1", "val1"},
		Tag{"key2", ""},
		Tag{"key3", "val3"},
		Tag{"key4", "val4"},
		Tag{"key5", "val5"},
		Tag{"key6", ""},
		Tag{"key7", ""},
		Tag{"key8", "val8"},
		Tag{"key9", "val9"},
		Tag{"key10", "val10"},
	}

	filter := []string{"key1", "key3", "key5", "key6", "key9", "key10"}

	for i := 0; i < b.N; i++ {
		tags.Filter(filter)
	}
}

func BenchmarkStringf(b *testing.B) {
	b.ResetTimer()

	tags := Tags{Tag{"aaa", "val1"}, Tag{"bbb", "val2"}, Tag{"ccc", "val3"}}
	for i := 0; i < b.N; i++ {
		tags.Stringf("{aaa}.requests.{bbb}.script")
	}
}

func BenchmarkString(b *testing.B) {
	tags := Tags{
		Tag{"key1", "val1"},
		Tag{"key2", ""},
		Tag{"key3", "val3"},
		Tag{"key4", "val4"},
		Tag{"key5", "val5"},
		Tag{"key6", ""},
		Tag{"key7", ""},
		Tag{"key8", "val8"},
		Tag{"key9", "val9"},
		Tag{"key10", "val10"},
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		tags.String()
	}
}
<|endoftext|>