<commit_before>package nasa

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"
)

// NewServer a http web-server that serves APOD pictures
//     / - today's APOD
//     /random-apod - returns a random APOD
//     TODO: /apod/YYYY-MM-DD - returns apod for specified date
func NewServer(listenAddr string) (*http.Server, error) {
	var err error
	tmpl, err = template.New("tmpl").Parse(tmplHTML)
	if err != nil {
		return nil, fmt.Errorf("unable to parse template: %v", err)
	}
	rh := &randomHandler{
		lastUpdate: time.Now().Add(-10 * time.Hour),
		cachedApod: &Image{},
		tmpl:       tmpl,
	}
	http.HandleFunc("/", handleIndex)
	http.Handle("/random-apod/", rh)

	return &http.Server{
		Addr:           listenAddr,
		ReadTimeout:    30 * time.Second,
		WriteTimeout:   60 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}, nil

}
func handleIndex(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return
	}
	apod, err := APODToday()
	if err != nil {
		http.Error(w, err.Error(), http.StatusServiceUnavailable)
		return
	}
	TmplData{Apod: *apod}.Render(w)
}

type randomHandler struct {
	tmpl *template.Template

	mu         sync.RWMutex // protects the values below
	lastUpdate time.Time
	cachedApod *Image
}

func (h *randomHandler) last() time.Time {
	h.mu.RLock()
	last := h.lastUpdate
	h.mu.RUnlock()
	return last
}
func (h *randomHandler) apod() Image {
	h.mu.RLock()
	apod := *h.cachedApod
	h.mu.RUnlock()
	return apod
}
func (h *randomHandler) update(apod Image, t time.Time) {
	h.mu.Lock()
	h.cachedApod = &apod
	h.lastUpdate = time.Now()
	h.mu.Unlock()

}

func (h *randomHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/random-apod/" {
		http.NotFound(w, r)
		return
	}
	apod := h.apod()

	// Update if cached apod is older than a second
	if time.Now().Sub(h.last()) > time.Second {
		if newApod, err := RandomAPOD(); err == nil {
			if newApod.URL != "" {
				apod = *newApod
			}
		}
		h.update(apod, time.Now())
	}

	td := TmplData{
		Apod:       h.apod(),
		SD:         r.URL.Query().Get("sd") != "",
		AutoReload: r.URL.Query().Get("auto") != "" || r.URL.Query().Get("interval") != "",
		Legacy:     r.URL.Query().Get("legacy") != "",
	}
	i := r.URL.Query().Get("interval")
	if i != "" {
		if n, err := strconv.Atoi(i); err == nil {
			td.AutoReloadInterval = n
		}
	}
	if td.AutoReloadInterval < 1 {
		td.AutoReloadInterval = 5 * 60 // default reload every 5 minutes
	}
	td.Render(w)
}

var tmpl *template.Template

// TmplData defines the data used to render the html template (tmpl)
type TmplData struct {
	Page               string
	Title              string
	Apod               Image
	SD                 bool // Standard definition display
	AutoReload         bool
	Legacy             bool // legacy browser does not support new reload
	AutoReloadInterval int
}

// Render returns an html to the responsewriter based on the template data
func (td TmplData) Render(wr http.ResponseWriter) {
	if td.Apod.URL == "" && td.Apod.HDURL == "" {
		http.Error(wr, "NASA API currently unavailable, it's experiencing downtime :(", http.StatusServiceUnavailable)
		return
	}
	if err := tmpl.Execute(wr, td); err != nil {
		log.Print(err)
	}
}

const tmplHTML = `<!DOCTYPE html>

<meta charset="UTF-8">
<title>{{with .Title}}{{.}}{{else}}NASA Astronomy Picture of the Day{{end}}</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
{{if .AutoReload -}}
{{if not .Legacy }}
<meta http-equiv="refresh" content="{{.AutoReloadInterval}}" >
{{end}}
{{end -}}

{{if and .AutoReload .Legacy}}

{{end}}

{{.Apod.Title}}

{{.Apod.Explanation}}

NASA Astronomy Picture of the Day {{.Apod.Date}} Open Image in HD

{{.Apod.Title}}

View in fullscreen (F11) for best experience ☺.
Reload random pic every 1 min, 10 min
{{.Title}}
This project is on Github.
Star

`
<commit_msg>Support Youtube videos for the nasa web page<commit_after>package nasa

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"
)

// NewServer a http web-server that serves APOD pictures
//     / - today's APOD
//     /random-apod - returns a random APOD
//     TODO: /apod/YYYY-MM-DD - returns apod for specified date
func NewServer(listenAddr string) (*http.Server, error) {
	var err error
	tmpl, err = template.New("tmpl").Parse(tmplHTML)
	if err != nil {
		return nil, fmt.Errorf("unable to parse template: %v", err)
	}
	rh := &randomHandler{
		lastUpdate: time.Now().Add(-10 * time.Hour),
		cachedApod: &Image{},
		tmpl:       tmpl,
	}
	http.HandleFunc("/", handleIndex)
	http.Handle("/random-apod/", rh)

	return &http.Server{
		Addr:           listenAddr,
		ReadTimeout:    30 * time.Second,
		IdleTimeout:    5 * time.Minute,
		WriteTimeout:   60 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}, nil

}
func handleIndex(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return
	}
	apod, err := APODToday()
	if err != nil {
		http.Error(w, err.Error(), http.StatusServiceUnavailable)
		return
	}
	TmplData{Apod: *apod}.Render(w)
}

type randomHandler struct {
	tmpl *template.Template

	mu         sync.RWMutex // protects the values below
	lastUpdate time.Time
	cachedApod *Image
}

func (h *randomHandler) last() time.Time {
	h.mu.RLock()
	last := h.lastUpdate
	h.mu.RUnlock()
	return last
}
func (h *randomHandler) apod() Image {
	h.mu.RLock()
	apod := *h.cachedApod
	h.mu.RUnlock()
	return apod
}
func (h *randomHandler) update(apod Image, t time.Time) {
	h.mu.Lock()
	h.cachedApod = &apod
	h.lastUpdate = time.Now()
	h.mu.Unlock()

}

func (h *randomHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/random-apod/" {
		http.NotFound(w, r)
		return
	}
	apod := h.apod()

	// Update if cached apod is older than a second
	if time.Now().Sub(h.last()) > time.Second {
		if newApod, err := RandomAPOD(); err == nil {
			if newApod.URL != "" {
				apod = *newApod
			}
		}
		h.update(apod, time.Now())
	}

	td := TmplData{
		Apod:       h.apod(),
		SD:         r.URL.Query().Get("sd") != "",
		AutoReload: r.URL.Query().Get("auto") != "" || r.URL.Query().Get("interval") != "",
		Legacy:     r.URL.Query().Get("legacy") != "",
	}
	i := r.URL.Query().Get("interval")
	if i != "" {
		if n, err := strconv.Atoi(i); err == nil {
			td.AutoReloadInterval = n
		}
	}
	if td.AutoReloadInterval < 1 {
		td.AutoReloadInterval = 5 * 60 // default reload every 5 minutes
	}
	td.Render(w)
}

var tmpl *template.Template

// TmplData defines the data used to render the html template (tmpl)
type TmplData struct {
	Page               string
	Title              string
	Apod               Image
	SD                 bool // Standard definition display
	AutoReload         bool
	Legacy             bool // legacy browser does not support new reload
	IsYoutube          bool
	AutoReloadInterval int
}

// Render returns an html to the responsewriter based on the template data
func (td TmplData) Render(wr http.ResponseWriter) {
	if strings.Contains(td.Apod.URL, "youtube") {
		td.IsYoutube = true
		if i := strings.Index(td.Apod.URL, "?"); i > 1 {
			td.Apod.URL = td.Apod.URL[:i]
		}
	}
	if td.Apod.URL == "" && td.Apod.HDURL == "" {
		http.Error(wr, "NASA API currently unavailable, it's experiencing downtime :(", http.StatusServiceUnavailable)
		return
	}
	if err := tmpl.Execute(wr, td); err != nil {
		log.Print(err)
	}
}

const tmplHTML = `<!DOCTYPE html>

<meta charset="UTF-8">
<title>{{with .Title}}{{.}}{{else}}NASA Astronomy Picture of the Day{{end}}</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
{{if .AutoReload -}}
{{if not .Legacy }}
<meta http-equiv="refresh" content="{{.AutoReloadInterval}}" >
{{end}}
{{end -}}

{{if and .AutoReload .Legacy}}

{{end}}

{{if .IsYoutube}}

{{else}}

{{end}}

{{.Apod.Title}}

{{.Apod.Explanation}}

NASA Astronomy Picture of the Day {{.Apod.Date}} Open Image in HD

{{.Apod.Title}}

View in fullscreen (F11) for best experience ☺.
Reload random pic every 1 min, 10 min
{{.Title}}
This project is on Github.
Star

`
<|endoftext|>


<commit_before>package main

import(
	"fmt"
	"net/http"
	"log"
	"strings"
	"strconv"
	"html/template"

	"github.com/kyledayton/requesthub/templates"
)

var config *Config

func foundationCSShandler(w http.ResponseWriter, r *http.Request) {
	f, _ := assets_foundation_css_bytes()
	w.Header().Set("Content-Type", "text/css")
	w.Write(f)
}

func foundationJShandler(w http.ResponseWriter, r *http.Request) {
	f, _ := assets_foundation_js_bytes()
	w.Header().Set("Content-Type", "application/javascript")
	w.Write(f)
}

func jqueryJShandler(w http.ResponseWriter, r *http.Request) {
	f, _ := assets_jquery_js_bytes()
	w.Header().Set("Content-Type", "application/javascript")
	w.Write(f)
}

func modernizrJShandler(w http.ResponseWriter, r *http.Request) {
	f, _ := assets_modernizr_js_bytes()
	w.Header().Set("Content-Type", "application/javascript")
	w.Write(f)
}

func authFailed(r *http.Request) bool {
	reqUser, reqPass, ok := r.BasicAuth()

	return config.AuthEnabled() && (!ok || reqUser != config.Username || reqPass != config.Password)
}

func requireAuth(w http.ResponseWriter) {
	w.Header().Add("WWW-Authenticate", "Basic realm=\"requesthub\"")
	w.WriteHeader(http.StatusUnauthorized)
	w.Write([]byte("Authorization Failed."))
}

func Start() {
	config = NewConfig()

	if config.AuthEnabled() {
		log.Printf("Using HTTP Basic Auth")
	}

	viewPage := template.Must(template.New("show").Parse(templates.SHOW_HUB))
	indexPage := template.Must(template.New("index").Parse(templates.INDEX))
	log.Printf("Initializing hub database (maxReq=%d)\n", config.MaxRequests)
	db := newHubDatabase(config.MaxRequests)

	forwardClient := new(http.Client)

	router := MakeRouter()

	router.HandleFunc(`/assets/foundation.css`, foundationCSShandler)
	router.HandleFunc(`/assets/foundation.js`, foundationJShandler)
	router.HandleFunc(`/assets/jquery.js`, jqueryJShandler)
	router.HandleFunc(`/assets/modernizr.js`, modernizrJShandler)

	router.HandleFunc(`/([\w\d\-_]+)/forward`, func(w http.ResponseWriter, r *http.Request) {
		if authFailed(r) {
			requireAuth(w)
			return
		}

		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]

		if hubName != "" {
			hub := db.Get(hubName)
			dest := strings.TrimSpace( r.FormValue("url") )

			if hub != nil {
				hub.ForwardURL = dest
			}
		}
	})

	router.HandleFunc(`/([\w\d\-_]+)/latest`, func(w http.ResponseWriter, r *http.Request) {
		if authFailed(r) {
			requireAuth(w)
			return
		}

		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]

		if hubName != "" {
			hub := db.Get(hubName)

			if hub != nil {
				w.Write([]byte(strconv.Itoa(int(hub.Requests.lastUpdate.Unix()))))
			}
		}
	})

	router.HandleFunc(`/([\w\d\-_]+)/delete`, func(w http.ResponseWriter, r *http.Request) {
		if authFailed(r) {
			requireAuth(w)
			return
		}

		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]

		if hubName != "" {
			hub := db.Get(hubName)

			if hub != nil {
				db.Delete(hub.Id)
				http.Redirect(w, r, "/", 302)
			}
		}
	})

	router.HandleFunc(`/([\w\d\-_]+)/requests`, func(w http.ResponseWriter, r *http.Request) {
		if authFailed(r) {
			requireAuth(w)
			return
		}

		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]

		if hubName != "" {
			hub := db.Get(hubName)

			if hub != nil {
				json, err := db.Get(hubName).Requests.ToJson()

				if err != nil {
					log.Panic(err)
				}

				w.Header().Add("Content-Type", "application/json")
				w.Write(json)
			}
		}
	})

	router.HandleFunc(`/([\d\w\-_]+)/clear`, func(w http.ResponseWriter, r *http.Request) {
		if authFailed(r) {
			requireAuth(w)
			return
		}

		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]
		hub := db.Get(hubName)

		if hub != nil {
			hub.Requests.Clear()
		}
	})

	router.HandleFunc(`/([\d\w\-_]+)`, func(w http.ResponseWriter, r *http.Request) {
		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]

		hub := db.Get(hubName)

		if hub != nil {
			if r.Method == "GET" {
				w.Header().Add("Content-Type", "text/html")

				if authFailed(r) {
					requireAuth(w)
					return
				}

				viewPage.Execute(w, hub)
			} else {
				req := hub.Requests.Insert(r)

				if hub.ForwardURL != "" {
					go req.Forward(forwardClient, hub.ForwardURL)
				}
			}
		}
	})

	router.HandleFunc(`/`, func(w http.ResponseWriter, r *http.Request) {

		if authFailed(r) {
			requireAuth(w)
			return
		}

		if r.Method == "GET" {
			w.Header().Add("Content-Type", "text/html")
			indexPage.Execute(w, db.hubs)
		} else if r.Method == "POST" {
			hubName := strings.TrimSpace( r.FormValue("hub_name") )

			if hubName == "" {
				http.Redirect(w, r, "/", 302)
				return
			}

			if db.Get(hubName) == nil {
				db.Create(hubName)
			}

			http.Redirect(w, r, fmt.Sprintf("/%s", hubName), 302)
		}
	})

	log.Printf("Listening on port %d\n", config.Port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", config.Port), router))
}
<commit_msg>Load yaml config on server boot<commit_after>package main

import(
	"fmt"
	"net/http"
	"log"
	"strings"
	"strconv"
	"html/template"

	"github.com/kyledayton/requesthub/templates"
)

var config *Config

func foundationCSShandler(w http.ResponseWriter, r *http.Request) {
	f, _ := assets_foundation_css_bytes()
	w.Header().Set("Content-Type", "text/css")
	w.Write(f)
}

func foundationJShandler(w http.ResponseWriter, r *http.Request) {
	f, _ := assets_foundation_js_bytes()
	w.Header().Set("Content-Type", "application/javascript")
	w.Write(f)
}

func jqueryJShandler(w http.ResponseWriter, r *http.Request) {
	f, _ := assets_jquery_js_bytes()
	w.Header().Set("Content-Type", "application/javascript")
	w.Write(f)
}

func modernizrJShandler(w http.ResponseWriter, r *http.Request) {
	f, _ := assets_modernizr_js_bytes()
	w.Header().Set("Content-Type", "application/javascript")
	w.Write(f)
}

func authFailed(r *http.Request) bool {
	reqUser, reqPass, ok := r.BasicAuth()

	return config.AuthEnabled() && (!ok || reqUser != config.Username || reqPass != config.Password)
}

func requireAuth(w http.ResponseWriter) {
	w.Header().Add("WWW-Authenticate", "Basic realm=\"requesthub\"")
	w.WriteHeader(http.StatusUnauthorized)
	w.Write([]byte("Authorization Failed."))
}

func Start() {
	config = NewConfig()

	log.Printf("Initializing hub database (maxReq=%d)\n", config.MaxRequests)
	db := newHubDatabase(config.MaxRequests)

	if config.HasYAMLConfig() {
		err := config.ApplyYAMLConfig(db)
		if err != nil {
			log.Printf("Error loading config file (%s): %s", config.YamlConfigFile, err)
		}
	}

	if config.AuthEnabled() {
		log.Printf("Using HTTP Basic Auth")
	}

	viewPage := template.Must(template.New("show").Parse(templates.SHOW_HUB))
	indexPage := template.Must(template.New("index").Parse(templates.INDEX))

	forwardClient := new(http.Client)

	router := MakeRouter()

	router.HandleFunc(`/assets/foundation.css`, foundationCSShandler)
	router.HandleFunc(`/assets/foundation.js`, foundationJShandler)
	router.HandleFunc(`/assets/jquery.js`, jqueryJShandler)
	router.HandleFunc(`/assets/modernizr.js`, modernizrJShandler)

	router.HandleFunc(`/([\w\d\-_]+)/forward`, func(w http.ResponseWriter, r *http.Request) {
		if authFailed(r) {
			requireAuth(w)
			return
		}

		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]

		if hubName != "" {
			hub := db.Get(hubName)
			dest := strings.TrimSpace( r.FormValue("url") )

			if hub != nil {
				hub.ForwardURL = dest
			}
		}
	})

	router.HandleFunc(`/([\w\d\-_]+)/latest`, func(w http.ResponseWriter, r *http.Request) {
		if authFailed(r) {
			requireAuth(w)
			return
		}

		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]

		if hubName != "" {
			hub := db.Get(hubName)

			if hub != nil {
				w.Write([]byte(strconv.Itoa(int(hub.Requests.lastUpdate.Unix()))))
			}
		}
	})

	router.HandleFunc(`/([\w\d\-_]+)/delete`, func(w http.ResponseWriter, r *http.Request) {
		if authFailed(r) {
			requireAuth(w)
			return
		}

		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]

		if hubName != "" {
			hub := db.Get(hubName)

			if hub != nil {
				db.Delete(hub.Id)
				http.Redirect(w, r, "/", 302)
			}
		}
	})

	router.HandleFunc(`/([\w\d\-_]+)/requests`, func(w http.ResponseWriter, r *http.Request) {
		if authFailed(r) {
			requireAuth(w)
			return
		}

		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]

		if hubName != "" {
			hub := db.Get(hubName)

			if hub != nil {
				json, err := db.Get(hubName).Requests.ToJson()

				if err != nil {
					log.Panic(err)
				}

				w.Header().Add("Content-Type", "application/json")
				w.Write(json)
			}
		}
	})

	router.HandleFunc(`/([\d\w\-_]+)/clear`, func(w http.ResponseWriter, r *http.Request) {
		if authFailed(r) {
			requireAuth(w)
			return
		}

		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]
		hub := db.Get(hubName)

		if hub != nil {
			hub.Requests.Clear()
		}
	})

	router.HandleFunc(`/([\d\w\-_]+)`, func(w http.ResponseWriter, r *http.Request) {
		parts := strings.Split(r.URL.Path, "/")
		hubName := parts[1]

		hub := db.Get(hubName)

		if hub != nil {
			if r.Method == "GET" {
				w.Header().Add("Content-Type", "text/html")

				if authFailed(r) {
					requireAuth(w)
					return
				}

				viewPage.Execute(w, hub)
			} else {
				req := hub.Requests.Insert(r)

				if hub.ForwardURL != "" {
					go req.Forward(forwardClient, hub.ForwardURL)
				}
			}
		}
	})

	router.HandleFunc(`/`, func(w http.ResponseWriter, r *http.Request) {

		if authFailed(r) {
			requireAuth(w)
			return
		}

		if r.Method == "GET" {
			w.Header().Add("Content-Type", "text/html")
			indexPage.Execute(w, db.hubs)
		} else if r.Method == "POST" {
			hubName := strings.TrimSpace( r.FormValue("hub_name") )

			if hubName == "" {
				http.Redirect(w, r, "/", 302)
				return
			}

			if db.Get(hubName) == nil {
				db.Create(hubName)
			}

			http.Redirect(w, r, fmt.Sprintf("/%s", hubName), 302)
		}
	})

	log.Printf("Listening on port %d\n", config.Port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", config.Port), router))
}
<|endoftext|>


<commit_before>package zalando

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"testing"
	"time"

	"github.com/zalando/gin-oauth2"
	"golang.org/x/oauth2"
)

// You have to have a current file $HOME/.chimp-token with only a
// valid Zalando access token.
var tokenFile string = fmt.Sprintf("%s/.chimp-token", os.Getenv("HOME"))

func getToken() (string, error) {
	file, err := os.Open(tokenFile)
	if err != nil {
		return "not a file", err
	}
	defer file.Close()

	data, err := ioutil.ReadAll(file)
	if err != nil {
		return "reading failed", err
	}
	return string(data), nil
}

func TestRequestTeamInfo(t *testing.T) {
	ginoauth2.AuthInfoURL = OAuth2Endpoint.TokenURL
	accessToken, err := getToken()
	if err != nil {
		fmt.Printf("ERR: Could not get Access Token from file, caused by %q.", accessToken)
		t.FailNow()
	}

	token := oauth2.Token{
		AccessToken: accessToken,
		TokenType:   "Bearer",
		Expiry:      time.Now().Add(time.Duration(600) * time.Second),
	}
	tc, err := ginoauth2.GetTokenContainer(&token)
	if err != nil {
		fmt.Printf("ERR: Could not get TokenContainer from ginoauth2.")
		t.FailNow()
	}
	resp, err := RequestTeamInfo(tc, TeamAPI)
	if err != nil {
		fmt.Printf("ERR: Could not get TeamInfo for TokenContainer from TeamAPI.")
		t.FailNow()
	}
	var data []TeamInfo
	err = json.Unmarshal(resp, &data)
	if err != nil {
		fmt.Printf("ERR: Could not unmarshal json data.")
		t.FailNow()
	}
	fmt.Printf("%+v\n", data)
}
<commit_msg>zalando/gin-oauth2#48 adding test for the bug<commit_after>package zalando

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http/httptest"
	"os"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"

	"github.com/gin-gonic/gin"

	"github.com/zalando/gin-oauth2"
	"golang.org/x/oauth2"
)

// You have to have a current file $HOME/.chimp-token with only a
// valid Zalando access token.
var tokenFile string = fmt.Sprintf("%s/.chimp-token", os.Getenv("HOME"))

func getToken() (string, error) {
	file, err := os.Open(tokenFile)
	if err != nil {
		return "not a file", err
	}
	defer file.Close()

	data, err := ioutil.ReadAll(file)
	if err != nil {
		return "reading failed", err
	}
	return string(data), nil
}

func TestRequestTeamInfo(t *testing.T) {
	ginoauth2.AuthInfoURL = OAuth2Endpoint.TokenURL
	accessToken, err := getToken()
	if err != nil {
		fmt.Printf("ERR: Could not get Access Token from file, caused by %q.", accessToken)
		t.FailNow()
	}

	token := oauth2.Token{
		AccessToken: accessToken,
		TokenType:   "Bearer",
		Expiry:      time.Now().Add(time.Duration(600) * time.Second),
	}
	tc, err := ginoauth2.GetTokenContainer(&token)
	if err != nil {
		fmt.Printf("ERR: Could not get TokenContainer from ginoauth2.")
		t.FailNow()
	}
	resp, err := RequestTeamInfo(tc, TeamAPI)
	if err != nil {
		fmt.Printf("ERR: Could not get TeamInfo for TokenContainer from TeamAPI.")
		t.FailNow()
	}
	var data []TeamInfo
	err = json.Unmarshal(resp, &data)
	if err != nil {
		fmt.Printf("ERR: Could not unmarshal json data.")
		t.FailNow()
	}
	fmt.Printf("%+v\n", data)
}

func TestScopeCheck(t *testing.T) {
	// given
	tc := &ginoauth2.TokenContainer{
		Token: &oauth2.Token{
			AccessToken:  "sdgergSgadGSAHBSHsagsdv.",
			TokenType:    "Bearer",
			RefreshToken: "",
		},
		Scopes: map[string]interface{}{
			"my-scope-1": true,
			"my-scope-2": true,
			"uid":        "stups_marilyn-updater",
		},
		GrantType: "password",
		Realm:     "/services",
	}
	ctx, _ := gin.CreateTestContext(httptest.NewRecorder())

	// when
	checkFn := ScopeCheck("name", "my-scope-1")
	result := checkFn(tc, ctx)

	// then
	assert.True(t, result)

	scopeVal, scopeOk := ctx.Get("my-scope-1")
	assert.True(t, scopeOk)
	assert.Equal(t, true, scopeVal)
}

func TestScopeAndCheck(t *testing.T) {
	// given
	tc := &ginoauth2.TokenContainer{
		Token: &oauth2.Token{
			AccessToken:  "sdgergSgadGSAHBSHsagsdv.",
			TokenType:    "Bearer",
			RefreshToken: "",
		},
		Scopes: map[string]interface{}{
			"my-scope-1": true,
			"my-scope-2": true,
			"uid":        "stups_marilyn-updater",
		},
		GrantType: "password",
		Realm:     "/services",
	}
	ctx, _ := gin.CreateTestContext(httptest.NewRecorder())

	// when
	checkFn := ScopeAndCheck("name", "uid", "my-scope-2")
	result := checkFn(tc, ctx)

	// then
	assert.True(t, result)

	uidVal, uidOk := ctx.Get("uid")
	scopeVal, scopeOk := ctx.Get("my-scope-2")
	assert.True(t, uidOk)
	assert.Equal(t, "stups_marilyn-updater", uidVal)
	assert.True(t, scopeOk)
	assert.Equal(t, true, scopeVal)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/dyatlov/go-oembed/oembed"
	"github.com/dyatlov/go-url2oembed/url2oembed"
	"github.com/jeffail/tunny"
)

type workerData struct {
	Status int
	Data   string
}

type apiWorker struct {
	Parser *url2oembed.Parser
}

type apiHandler struct {
}

func (h *apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	u := r.FormValue("url")

	w.Header().Set("Server", "ProcLink")
	w.Header().Set("Content-Type", "application/json")

	// to be able to retrieve data from javascript directly
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET")

	_, err := url.Parse(u)

	if err != nil {
		log.Printf("Invalid URL provided: %s", u)
		http.Error(w, "{\"status\": \"error\", \"message\":\"Invalid URL\"}", 500)
		return
	}

	result, err := workerPool.SendWork(u)

	if err != nil {
		log.Printf("An unknown error occured: %s", err.Error())

		http.Error(w, "{\"status\": \"error\", \"message\":\"Internal error\"}", 500)
		return
	}

	if data, ok := result.(*workerData); ok {
		w.WriteHeader(data.Status)
		fmt.Fprintln(w, data.Data)
		return
	}

	log.Print("Unable to decode worker result")

	http.Error(w, "{\"status\": \"error\", \"message\":\"Unable to decode worker result\"}", 500)
}

// Use this call to block further jobs if necessary
func (worker *apiWorker) TunnyReady() bool {
	return true
}

// This is where the work actually happens
func (worker *apiWorker) TunnyJob(data interface{}) interface{} {
	if u, ok := data.(string); ok {
		u = strings.Trim(u, "\r\n")

		log.Printf("Got url: %s", u)

		info := worker.Parser.Parse(u)

		if info == nil {
			log.Printf("No info for url: %s", u)

			return &workerData{Status: 404, Data: "{\"status\": \"error\", \"message\":\"Unable to retrieve information from provided url\"}"}
		}
		if info.Status < 300 {
			log.Printf("Url parsed: %s", u)

			return &workerData{Status: 200, Data: info.String()}
		}

		log.Printf("Something weird: %s", u)

		return &workerData{Status: 411, Data: fmt.Sprintf("{\"status\": \"error\", \"message\":\"Unable to obtain data. Status code: %d\"}", info.Status)}
	}

	return &workerData{Status: 500, Data: "{\"status\": \"error\", \"message\":\"Something weird happened\"}"}
}

var workerPool *tunny.WorkPool

// stringsToNetworks converts arrays of string representation of IP ranges into []*net.IPnet slice
func stringsToNetworks(ss []string) ([]*net.IPNet, error) {
	var result []*net.IPNet
	for _, s := range ss {
		_, network, err := net.ParseCIDR(s)
		if err != nil {
			return nil, err
		}
		result = append(result, network)
	}

	return result, nil
}

func main() {
	providersFile := flag.String("providers_file", "providers.json", "Path to oembed providers json file")
	workerCount := flag.Int64("worker_count", 1000, "Amount of workers to start")
	host := flag.String("host", "localhost", "Host to listen on")
	port := flag.Int("port", 8000, "Port to listen on")
	maxHTMLBytesToRead := flag.Int64("html_bytes_to_read", 50000, "How much data to read from URL if it's an html page")
	maxBinaryBytesToRead := flag.Int64("binary_bytes_to_read", 4096, "How much data to read from URL if it's NOT an html page")
	waitTimeout := flag.Int("wait_timeout", 7, "How much time to wait for/fetch response from remote server")
	whiteListRanges := flag.String("whitelist_ranges", "", "What IP ranges to allow. Example: 178.25.32.1/8")
	blackListRanges := flag.String("blacklist_ranges", "", "What IP ranges to disallow. Example: 178.25.32.1/8")

	flag.Parse()

	buf, err := ioutil.ReadFile(*providersFile)

	if err != nil {
		panic(err)
	}

	var whiteListNetworks []*net.IPNet
	if len(*whiteListRanges) > 0 {
		if whiteListNetworks, err = stringsToNetworks(strings.Split(*whiteListRanges, " ")); err != nil {
			panic(err)
		}
	}

	var blackListNetworks []*net.IPNet
	if len(*blackListRanges) > 0 {
		if blackListNetworks, err = stringsToNetworks(strings.Split(*blackListRanges, " ")); err != nil {
			panic(err)
		}
	}

	oe := oembed.NewOembed()
	oe.ParseProviders(bytes.NewReader(buf))

	workers := make([]tunny.TunnyWorker, *workerCount)
	for i := range workers {
		p := url2oembed.NewParser(oe)
		p.MaxHTMLBodySize = *maxHTMLBytesToRead
		p.MaxBinaryBodySize = *maxBinaryBytesToRead
		p.WaitTimeout = time.Duration(*waitTimeout) * time.Second
		p.BlacklistedIPNetworks = blackListNetworks
		p.WhitelistedIPNetworks = whiteListNetworks
		workers[i] = &(apiWorker{Parser: p})
	}

	pool, err := tunny.CreateCustomPool(workers).Open()

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

	defer pool.Close()

	workerPool = pool

	startServer(*host, *port, *waitTimeout)
}

func startServer(host string, port int, waitTimeout int) {
	s := &http.Server{
		Addr:           fmt.Sprintf("%s:%d", host, port),
		Handler:        &apiHandler{},
		ReadTimeout:    time.Duration(waitTimeout) * time.Second,
		WriteTimeout:   time.Duration(waitTimeout) * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	log.Fatal(s.ListenAndServe())
}
<commit_msg>removed bloated jeffail/tunny and replaced with simple channels<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/dyatlov/go-oembed/oembed"
	"github.com/dyatlov/go-url2oembed/url2oembed"
)

type workerData struct {
	Status int
	Data   string
}

type job struct {
	Url    string
	Result chan workerData
}

type apiHandler struct {
}

func (h *apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	u := r.FormValue("url")

	w.Header().Set("Server", "ProcLink")
	w.Header().Set("Content-Type", "application/json")

	// to be able to retrieve data from javascript directly
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET")

	_, err := url.Parse(u)

	if err != nil {
		log.Printf("Invalid URL provided: %s", u)
		http.Error(w, "{\"status\": \"error\", \"message\":\"Invalid URL\"}", 500)
		return
	}

	log.Printf("Sending job: %s", u)

	c := make(chan workerData)
	jobPool <- job{Url: u, Result: c}
	data := <-c

	w.WriteHeader(data.Status)
	fmt.Fprintln(w, data.Data)
}

// This is where the work actually happens
func worker(parser *url2oembed.Parser, jobs <-chan job) {
	for {
		params := <-jobs
		u := strings.Trim(params.Url, "\r\n")

		log.Printf("Got url: %s", u)

		info := parser.Parse(u)

		if info == nil {
			log.Printf("No info for url: %s", u)
			params.Result <- workerData{Status: 404, Data: "{\"status\": \"error\", \"message\":\"Unable to retrieve information from provided url\"}"}
		} else if info.Status < 300 {
			log.Printf("Url parsed: %s", u)
			params.Result <- workerData{Status: 200, Data: info.String()}
		} else {
			log.Printf("Something weird: %s", u)
			params.Result <- workerData{Status: 411, Data: fmt.Sprintf("{\"status\": \"error\", \"message\":\"Unable to obtain data. Status code: %d\"}", info.Status)}
		}
	}
}

var jobPool chan job

// stringsToNetworks converts arrays of string representation of IP ranges into []*net.IPnet slice
func stringsToNetworks(ss []string) ([]*net.IPNet, error) {
	var result []*net.IPNet
	for _, s := range ss {
		_, network, err := net.ParseCIDR(s)
		if err != nil {
			return nil, err
		}
		result = append(result, network)
	}

	return result, nil
}

func main() {
	providersFile := flag.String("providers_file", "providers.json", "Path to oembed providers json file")
	workerCount := flag.Int("worker_count", 1000, "Amount of workers to start")
	host := flag.String("host", "localhost", "Host to listen on")
	port := flag.Int("port", 8000, "Port to listen on")
	maxHTMLBytesToRead := flag.Int64("html_bytes_to_read", 50000, "How much data to read from URL if it's an html page")
	maxBinaryBytesToRead := flag.Int64("binary_bytes_to_read", 4096, "How much data to read from URL if it's NOT an html page")
	waitTimeout := flag.Int("wait_timeout", 7, "How much time to wait for/fetch response from remote server")
	whiteListRanges := flag.String("whitelist_ranges", "", "What IP ranges to allow. Example: 178.25.32.1/8")
	blackListRanges := flag.String("blacklist_ranges", "", "What IP ranges to disallow. Example: 178.25.32.1/8")

	flag.Parse()

	buf, err := ioutil.ReadFile(*providersFile)

	if err != nil {
		panic(err)
	}

	var whiteListNetworks []*net.IPNet
	if len(*whiteListRanges) > 0 {
		if whiteListNetworks, err = stringsToNetworks(strings.Split(*whiteListRanges, " ")); err != nil {
			panic(err)
		}
	}

	var blackListNetworks []*net.IPNet
	if len(*blackListRanges) > 0 {
		if blackListNetworks, err = stringsToNetworks(strings.Split(*blackListRanges, " ")); err != nil {
			panic(err)
		}
	}

	oe := oembed.NewOembed()
	oe.ParseProviders(bytes.NewReader(buf))

	log.Println("Starting workers:", *workerCount)

	jobPool = make(chan job)
	for i := 0; i < *workerCount; i++ {
		p := url2oembed.NewParser(oe)
		p.MaxHTMLBodySize = *maxHTMLBytesToRead
		p.MaxBinaryBodySize = *maxBinaryBytesToRead
		p.WaitTimeout = time.Duration(*waitTimeout) * time.Second
		p.BlacklistedIPNetworks = blackListNetworks
		p.WhitelistedIPNetworks = whiteListNetworks
		go worker(p, jobPool)
	}

	log.Println("All workers started. Starting server on port", *port)

	startServer(*host, *port, *waitTimeout)
}

func startServer(host string, port int, waitTimeout int) {
	s := &http.Server{
		Addr:           fmt.Sprintf("%s:%d", host, port),
		Handler:        &apiHandler{},
		ReadTimeout:    time.Duration(waitTimeout) * time.Second,
		WriteTimeout:   time.Duration(waitTimeout) * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	log.Fatal(s.ListenAndServe())
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/mitchellh/colorstring"
	"log"
	"time"
)

type SyncServer struct {
	Spotify  *Spotify
	Radio    *Radio
	Interval time.Duration
	playlist *Playlist
}

func logColorf(format string, v ...interface{}) {
	log.Printf(colorstring.Color(format), v...)
}

func (sync *SyncServer) Serve() {
	ticker := time.NewTicker(sync.Interval * time.Minute)

	spotifyPlaylist, err := sync.Spotify.GetOrCreatePlaylist(
		sync.Radio.Name)
	if err != nil {
		log.Fatalf("Failed to get or create playlist: %s", err)
	}
	sync.playlist = spotifyPlaylist

	logColorf("Server started. Syncing every [bold]%d[reset] minute(s)",
		sync.Interval)
	logColorf("[green]Tracks will be added to Spotify playlist: %s[reset]",
		spotifyPlaylist.String())
	f := func() {
		logColorf("[light_magenta]Running sync[reset]")
		if err := sync.run(); err != nil {
			log.Printf("Sync failed: %s\n", err)
		}
	}
	f()
	for {
		select {
		case <-ticker.C:
			f()
		}
	}
}

func (sync *SyncServer) run() error {
	radioPlaylist, err := sync.Radio.Playlist()
	if err != nil {
		return err
	}

	radioTracks := radioPlaylist.Tracks[1:] // Skip previous track
	if current, err := radioPlaylist.Current(); err != nil {
		logColorf("[red]Failed to get current track: %s[reset]", err)
	} else {
		if position, err := current.Position(); err != nil {
			logColorf("[red]Failed to parse metadata: %s[reset]",
				err)
		} else {
			logColorf("[cyan]%s is currently playing: %s - %s"+
				"[reset] (%s) [%s]",
				sync.Radio.Name, current.Artist, current.Track,
				position.String(),
				position.Symbol(10, true))
		}
	}

	for _, t := range radioTracks {
		logColorf("Searching for: %s", t.String())
		if !t.IsMusic() {
			logColorf("[green]Not music, skipping: %s[reset]",
				t.String())
			continue
		}
		track, err := sync.Spotify.SearchArtistTrack(t.Artist, t.Track)
		if err != nil {
			logColorf("[red]Not found: %s (%s)[reset]",
				t.String(), err)
			continue
		}
		if sync.playlist.Contains(*track) {
			logColorf("[yellow]Already added: %s[reset]",
				track.String())
			continue
		}
		if err = sync.Spotify.AddTrack(sync.playlist,
			track); err != nil {
			logColorf("[red]Failed to add: %s (%s)[reset]",
				track.String(), err)
			continue
		}
		// Refresh playlist
		playlist, err := sync.Spotify.PlaylistById(sync.playlist.Id)
		if err != nil {
			logColorf("[red]Failed to refresh playlist: %s[reset]",
				err)
			continue
		}
		sync.playlist = playlist
		logColorf("[green]Added track: %s[reset]", track.String())
	}
	return nil
}
<commit_msg>Use LRU cache for synced tracks<commit_after>package main

import (
	"github.com/golang/groupcache/lru"
	"github.com/mitchellh/colorstring"
	"log"
	"time"
)

type SyncServer struct {
	Spotify  *Spotify
	Radio    *Radio
	Interval time.Duration
	playlist *Playlist
	cache    *lru.Cache
}

func logColorf(format string, v ...interface{}) {
	log.Printf(colorstring.Color(format), v...)
}

func (sync *SyncServer) isCached(track *Track) bool {
	_, exists := sync.cache.Get(track.Id)
	return exists
}

func (sync *SyncServer) addTrack(track *Track) {
	if !sync.isCached(track) {
		sync.cache.Add(track.Id, track)
	}
}

func (sync *SyncServer) initPlaylist() error {
	playlist, err := sync.Spotify.GetOrCreatePlaylist(sync.Radio.Name)
	if err != nil {
		return err
	}
	sync.playlist = playlist
	return nil
}

func (sync *SyncServer) initCache() {
	sync.cache = lru.New(100)
	for _, t := range sync.playlist.Tracks.Items {
		sync.addTrack(&t.Track)
	}
}

func (sync *SyncServer) Serve() {
	ticker := time.NewTicker(sync.Interval * time.Minute)

	logColorf("Server started. Syncing every [bold]%d[reset] minute(s)",
		sync.Interval)

	if err := sync.initPlaylist(); err != nil {
		log.Fatalf("Failed to get or create playlist: %s", err)
	}
	log.Printf("Playlist has %d entries", len(sync.playlist.Tracks.Items))
	sync.initCache()

	logColorf("[green]Tracks will be added to Spotify playlist: %s[reset]",
		sync.playlist.String())
	f := func() {
		logColorf("[light_magenta]Running sync[reset]")
		if err := sync.run(); err != nil {
			log.Printf("Sync failed: %s\n", err)
		}
	}
	f()
	for {
		select {
		case <-ticker.C:
			f()
		}
	}
}

func (sync *SyncServer) run() error {
	radioPlaylist, err := sync.Radio.Playlist()
	if err != nil {
		return err
	}

	radioTracks := radioPlaylist.Tracks[1:] // Skip previous track
	if current, err := radioPlaylist.Current(); err != nil {
		logColorf("[red]Failed to get current track: %s[reset]", err)
	} else {
		if position, err := current.Position(); err != nil {
			logColorf("[red]Failed to parse metadata: %s[reset]",
				err)
		} else {
			logColorf("[cyan]%s is currently playing: %s - %s"+
				"[reset] (%s) [%s]",
				sync.Radio.Name, current.Artist, current.Track,
				position.String(),
				position.Symbol(10, true))
		}
	}

	for _, t := range radioTracks {
		logColorf("Searching for: %s", t.String())
		if !t.IsMusic() {
			logColorf("[green]Not music, skipping: %s[reset]",
				t.String())
			continue
		}
		track, err := sync.Spotify.SearchArtistTrack(t.Artist, t.Track)
		if err != nil {
			logColorf("[red]Not found: %s (%s)[reset]",
				t.String(), err)
			continue
		}
		if sync.isCached(track) {
			logColorf("[yellow]Already added: %s[reset]",
				track.String())
			continue
		}
		if err = sync.Spotify.AddTrack(sync.playlist,
			track); err != nil {
			logColorf("[red]Failed to add: %s (%s)[reset]",
				track.String(), err)
			continue
		}
		sync.addTrack(track)
		logColorf("[green]Added track: %s (cache size: %d)[reset]",
			track.String(), sync.cache.Len())
	}
	return nil
}
<|endoftext|>


<commit_before>package waddell

import (
	"crypto/tls"
	"fmt"
	"net"
	"sync"

	"github.com/getlantern/framed"
	"github.com/getlantern/tlsdefaults"
	"github.com/oxtoacart/bpool"
)

const (
	DefaultNumBuffers = 10000
)

var (
	// The ECDHE cipher suites are preferred for performance and forward
	// secrecy.  See https://community.qualys.com/blogs/securitylabs/2013/06/25/ssl-labs-deploying-forward-secrecy.
	preferredCipherSuites = []uint16{
		tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
		tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
		tls.TLS_RSA_WITH_RC4_128_SHA,
		tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
		tls.TLS_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
		tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
	}
)

// Server is a waddell server
type Server struct {
	// NumBuffers: number of buffers to cache for reading and writing (balances
	// overall memory consumption against CPU usage).  Defaults to 10,000.
	NumBuffers int

	// BufferBytes: size of each buffer (this places a cap on the maxmimum
	// message size that can be transmitted).  Defaults to 65,535.
	BufferBytes int

	peers      map[PeerId]*peer // connected peers by id
	peersMutex sync.RWMutex     // protects access to peers map
	buffers    *bpool.BytePool  // pool of buffers for reading/writing
}

type peer struct {
	server *Server
	id     PeerId
	conn   net.Conn
	reader *framed.Reader
	writer *framed.Writer
}

// Listen creates a listener at the given address. pkfile and certfile are
// optional. If both are specified, connections will be secured with TLS.
func Listen(addr string, pkfile string, certfile string) (net.Listener, error) {
	if (pkfile != "" && certfile == "") || (pkfile == "" && certfile != "") {
		return nil, fmt.Errorf("Please specify both pkfile and certfile")
	}
	if pkfile != "" {
		return listenTLS(addr, pkfile, certfile)
	} else {
		return net.Listen("tcp", addr)
	}
}

func listenTLS(addr string, pkfile string, certfile string) (net.Listener, error) {
	cert, err := tls.LoadX509KeyPair(certfile, pkfile)
	if err != nil {
		return nil, fmt.Errorf("Unable to load cert and pk: %s", err)
	}

	cfg := tlsdefaults.Server()
	cfg.Certificates = []tls.Certificate{cert}
	return tls.Listen("tcp", addr, cfg)
}

// Serve starts the waddell server using the given listener
func (server *Server) Serve(listener net.Listener) error {
	// Set default values
	if server.NumBuffers == 0 {
		server.NumBuffers = DefaultNumBuffers
	}
	if server.BufferBytes == 0 {
		server.BufferBytes = framed.MAX_FRAME_SIZE
	}

	server.buffers = bpool.NewBytePool(server.NumBuffers, server.BufferBytes)
	server.peers = make(map[PeerId]*peer)

	for {
		conn, err := listener.Accept()
		if err != nil {
			return fmt.Errorf("Error accepting connection: %s", err)
		}
		c := server.addPeer(&peer{
			server: server,
			id:     randomPeerId(),
			conn:   conn,
			reader: framed.NewReader(conn),
			writer: framed.NewWriter(conn),
		})
		go c.run()
	}
}

func (server *Server) addPeer(c *peer) *peer {
	server.peersMutex.Lock()
	defer server.peersMutex.Unlock()
	server.peers[c.id] = c
	return c
}

func (server *Server) getPeer(id PeerId) *peer {
	server.peersMutex.RLock()
	defer server.peersMutex.RUnlock()
	return server.peers[id]
}

func (server *Server) removePeer(id PeerId) {
	server.peersMutex.Lock()
	defer server.peersMutex.Unlock()
	delete(server.peers, id)
}

func (peer *peer) run() {
	defer peer.conn.Close()
	defer peer.server.removePeer(peer.id)

	// Tell the peer its id
	msg := peer.server.buffers.Get()[:PEER_ID_LENGTH]
	peer.id.write(msg)
	_, err := peer.writer.Write(msg)
	if err != nil {
		log.Debugf("Unable to send peerid on connect: %s", err)
		return
	}

	// Read messages until there are no more to read
	for {
		if !peer.readNext() {
			return
		}
	}
}

func (peer *peer) readNext() (ok bool) {
	b := peer.server.buffers.Get()
	defer peer.server.buffers.Put(b)
	n, err := peer.reader.Read(b)
	if err != nil {
		return false
	}
	msg := b[:n]
	if len(msg) == 1 && msg[0] == keepAlive[0] {
		// Got a keepalive message, ignore it
		return true
	}
	to, err := readPeerId(msg)
	if err != nil {
		// Problem determining recipient
		log.Errorf("Unable to determine recipient: ", err.Error())
		return true
	}
	cto := peer.server.getPeer(to)
	if cto == nil {
		// Recipient not found
		return true
	}
	// Set sender's id as the id in the message
	err = peer.id.write(msg)
	if err != nil {
		return true
	}
	_, err = cto.writer.Write(msg)
	if err != nil {
		cto.conn.Close()
		return true
	}
	return true
}
<commit_msg>Forcing TLS 1.2<commit_after>package waddell

import (
	"crypto/tls"
	"fmt"
	"net"
	"sync"

	"github.com/getlantern/framed"
	"github.com/getlantern/tlsdefaults"
	"github.com/oxtoacart/bpool"
)

const (
	DefaultNumBuffers = 10000
)

var (
	// The ECDHE cipher suites are preferred for performance and forward
	// secrecy.  See https://community.qualys.com/blogs/securitylabs/2013/06/25/ssl-labs-deploying-forward-secrecy.
	preferredCipherSuites = []uint16{
		tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
		tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
		tls.TLS_RSA_WITH_RC4_128_SHA,
		tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
		tls.TLS_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
		tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
	}
)

// Server is a waddell server
type Server struct {
	// NumBuffers: number of buffers to cache for reading and writing (balances
	// overall memory consumption against CPU usage).  Defaults to 10,000.
	NumBuffers int

	// BufferBytes: size of each buffer (this places a cap on the maxmimum
	// message size that can be transmitted).  Defaults to 65,535.
	BufferBytes int

	peers      map[PeerId]*peer // connected peers by id
	peersMutex sync.RWMutex     // protects access to peers map
	buffers    *bpool.BytePool  // pool of buffers for reading/writing
}

type peer struct {
	server *Server
	id     PeerId
	conn   net.Conn
	reader *framed.Reader
	writer *framed.Writer
}

// Listen creates a listener at the given address. pkfile and certfile are
// optional. If both are specified, connections will be secured with TLS.
func Listen(addr string, pkfile string, certfile string) (net.Listener, error) {
	if (pkfile != "" && certfile == "") || (pkfile == "" && certfile != "") {
		return nil, fmt.Errorf("Please specify both pkfile and certfile")
	}
	if pkfile != "" {
		return listenTLS(addr, pkfile, certfile)
	} else {
		return net.Listen("tcp", addr)
	}
}

func listenTLS(addr string, pkfile string, certfile string) (net.Listener, error) {
	cert, err := tls.LoadX509KeyPair(certfile, pkfile)
	if err != nil {
		return nil, fmt.Errorf("Unable to load cert and pk: %s", err)
	}

	cfg := tlsdefaults.Server()
	cfg.MinVersion = tls.VersionTLS12 // force newest available version of TLS
	cfg.Certificates = []tls.Certificate{cert}
	return tls.Listen("tcp", addr, cfg)
}

// Serve starts the waddell server using the given listener
func (server *Server) Serve(listener net.Listener) error {
	// Set default values
	if server.NumBuffers == 0 {
		server.NumBuffers = DefaultNumBuffers
	}
	if server.BufferBytes == 0 {
		server.BufferBytes = framed.MAX_FRAME_SIZE
	}

	server.buffers = bpool.NewBytePool(server.NumBuffers, server.BufferBytes)
	server.peers = make(map[PeerId]*peer)

	for {
		conn, err := listener.Accept()
		if err != nil {
			return fmt.Errorf("Error accepting connection: %s", err)
		}
		c := server.addPeer(&peer{
			server: server,
			id:     randomPeerId(),
			conn:   conn,
			reader: framed.NewReader(conn),
			writer: framed.NewWriter(conn),
		})
		go c.run()
	}
}

func (server *Server) addPeer(c *peer) *peer {
	server.peersMutex.Lock()
	defer server.peersMutex.Unlock()
	server.peers[c.id] = c
	return c
}

func (server *Server) getPeer(id PeerId) *peer {
	server.peersMutex.RLock()
	defer server.peersMutex.RUnlock()
	return server.peers[id]
}

func (server *Server) removePeer(id PeerId) {
	server.peersMutex.Lock()
	defer server.peersMutex.Unlock()
	delete(server.peers, id)
}

func (peer *peer) run() {
	defer peer.conn.Close()
	defer peer.server.removePeer(peer.id)

	// Tell the peer its id
	msg := peer.server.buffers.Get()[:PEER_ID_LENGTH]
	peer.id.write(msg)
	_, err := peer.writer.Write(msg)
	if err != nil {
		log.Debugf("Unable to send peerid on connect: %s", err)
		return
	}

	// Read messages until there are no more to read
	for {
		if !peer.readNext() {
			return
		}
	}
}

func (peer *peer) readNext() (ok bool) {
	b := peer.server.buffers.Get()
	defer peer.server.buffers.Put(b)
	n, err := peer.reader.Read(b)
	if err != nil {
		return false
	}
	msg := b[:n]
	if len(msg) == 1 && msg[0] == keepAlive[0] {
		// Got a keepalive message, ignore it
		return true
	}
	to, err := readPeerId(msg)
	if err != nil {
		// Problem determining recipient
		log.Errorf("Unable to determine recipient: ", err.Error())
		return true
	}
	cto := peer.server.getPeer(to)
	if cto == nil {
		// Recipient not found
		return true
	}
	// Set sender's id as the id in the message
	err = peer.id.write(msg)
	if err != nil {
		return true
	}
	_, err = cto.writer.Write(msg)
	if err != nil {
		cto.conn.Close()
		return true
	}
	return true
}
<|endoftext|>


<commit_before>package parser

import "github.com/Zac-Garby/pluto/token"
import "github.com/Zac-Garby/pluto/ast"

const (
	lowest = iota
	assign
	question
	or
	and
	bitOr
	bitAnd
	equals
	compare
	sum
	product
	exp
	prefix
	methodCall
	index
)

var precedences = map[token.Type]int{
	token.Assign:             assign,
	token.Declare:            assign,
	token.AndEquals:          assign,
	token.BitAndEquals:       assign,
	token.BitOrEquals:        assign,
	token.ExpEquals:          assign,
	token.FloorDivEquals:     assign,
	token.MinusEquals:        assign,
	token.ModEquals:          assign,
	token.OrEquals:           assign,
	token.PlusEquals:         assign,
	token.QuestionMarkEquals: assign,
	token.SlashEquals:        assign,
	token.StarEquals:         assign,
	token.QuestionMark:       question,
	token.Or:                 or,
	token.And:                and,
	token.BitOr:              bitOr,
	token.BitAnd:             bitAnd,
	token.Equal:              equals,
	token.NotEqual:           equals,
	token.LessThan:           compare,
	token.GreaterThan:        compare,
	token.LessThanEq:         compare,
	token.GreaterThanEq:      compare,
	token.Plus:               sum,
	token.Minus:              sum,
	token.Star:               product,
	token.Slash:              product,
	token.Mod:                product,
	token.Exp:                exp,
	token.FloorDiv:           exp,
	token.Bang:               prefix,
	token.Colon:              methodCall,
	token.DoubleColon:        methodCall,
	token.Dot:                index,
	token.LeftSquare:         index,
}

var argBlacklist = []token.Type{
	token.If,
	token.BackSlash,
	token.While,
	token.For,
	token.Match,
	token.Minus,
	token.Plus,
	token.LeftSquare,
	token.Try,
	token.Bang,
}

func isBlacklisted(t token.Type) bool {
	for _, blacklisted := range argBlacklist {
		if t == blacklisted {
			return true
		}
	}

	return false
}

func isArgNode(n ast.Node) bool {
	_, ok := n.(ast.Expression)
	return ok
}
<commit_msg>Fix x < y parsing<commit_after>package parser

import "github.com/Zac-Garby/pluto/token"
import "github.com/Zac-Garby/pluto/ast"

const (
	lowest = iota
	assign
	question
	or
	and
	bitOr
	bitAnd
	equals
	compare
	sum
	product
	exp
	prefix
	methodCall
	index
)

var precedences = map[token.Type]int{
	token.Assign:             assign,
	token.Declare:            assign,
	token.AndEquals:          assign,
	token.BitAndEquals:       assign,
	token.BitOrEquals:        assign,
	token.ExpEquals:          assign,
	token.FloorDivEquals:     assign,
	token.MinusEquals:        assign,
	token.ModEquals:          assign,
	token.OrEquals:           assign,
	token.PlusEquals:         assign,
	token.QuestionMarkEquals: assign,
	token.SlashEquals:        assign,
	token.StarEquals:         assign,
	token.QuestionMark:       question,
	token.Or:                 or,
	token.And:                and,
	token.BitOr:              bitOr,
	token.BitAnd:             bitAnd,
	token.Equal:              equals,
	token.NotEqual:           equals,
	token.LessThan:           compare,
	token.GreaterThan:        compare,
	token.LessThanEq:         compare,
	token.GreaterThanEq:      compare,
	token.Plus:               sum,
	token.Minus:              sum,
	token.Star:               product,
	token.Slash:              product,
	token.Mod:                product,
	token.Exp:                exp,
	token.FloorDiv:           exp,
	token.Bang:               prefix,
	token.Colon:              methodCall,
	token.DoubleColon:        methodCall,
	token.Dot:                index,
	token.LeftSquare:         index,
}

var argBlacklist = []token.Type{
	token.If,
	token.BackSlash,
	token.While,
	token.For,
	token.Match,
	token.Minus,
	token.Plus,
	token.LeftSquare,
	token.Try,
	token.Bang,
	token.LessThan,
}

func isBlacklisted(t token.Type) bool {
	for _, blacklisted := range argBlacklist {
		if t == blacklisted {
			return true
		}
	}

	return false
}

func isArgNode(n ast.Node) bool {
	_, ok := n.(ast.Expression)
	return ok
}
<|endoftext|>


<commit_before>package air

import (
	"crypto/tls"
	"net"
	"net/http"
	"time"
)

// server represents the HTTP server. It's embedded with `http.Server`.
type server struct {
	*http.Server

	air *Air
}

// newServer returns a pointer of a new instance of `server`.
func newServer(a *Air) *server {
	s := &server{
		Server: &http.Server{},
		air:    a,
	}
	s.Addr = s.air.Config.Address
	s.Handler = s
	s.ReadTimeout = s.air.Config.ReadTimeout
	s.WriteTimeout = s.air.Config.WriteTimeout
	return s
}

// start starts the HTTP server.
func (s *server) start() error {
	cl := s.air.Config.Listener
	if cl != nil {
		return s.Serve(cl)
	}

	ln, err := net.Listen("tcp", s.air.Config.Address)
	if err != nil {
		return err
	}

	ctcf := s.air.Config.TLSCertFile
	ctkf := s.air.Config.TLSKeyFile
	if ctcf != "" && ctkf != "" {
		tlscfg := &tls.Config{}
		if !s.air.Config.DisableHTTP2 {
			tlscfg.NextProtos = append(tlscfg.NextProtos, "h2")
		}
		tlscfg.Certificates = make([]tls.Certificate, 1)
		tlscfg.Certificates[0], err = tls.LoadX509KeyPair(ctcf, ctkf)
		if err != nil {
			return err
		}
		cl = tls.NewListener(
			tcpKeepAliveListener{ln.(*net.TCPListener)},
			tlscfg,
		)
	} else {
		cl = tcpKeepAliveListener{ln.(*net.TCPListener)}
	}

	return s.Serve(cl)
}

// stop stops the HTTP server.
func (s *server) stop() error {
	return s.air.Config.Listener.Close()
}

// ServeHTTP implements the `http.Handler`.
func (s *server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	c := contextPool.Get().(*Context)
	c.feed(rw, req)

	// Gases
	h := func(c *Context) error {
		method := c.Request.Method
		path := c.Request.URL.EscapedPath()
		s.air.router.route(method, path, c)
		h := c.Handler
		for i := len(s.air.gases) - 1; i >= 0; i-- {
			h = s.air.gases[i](h)
		}
		return h(c)
	}

	// Pregases
	for i := len(s.air.pregases) - 1; i >= 0; i-- {
		h = s.air.pregases[i](h)
	}

	// Execute chain
	if err := h(c); err != nil {
		s.air.HTTPErrorHandler(err, c)
	}

	c.reset()
	contextPool.Put(c)
}

// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted connections. It's used by
// ListenAndServe and ListenAndServeTLS so dead TCP connections (e.g. closing laptop mid-download)
// eventually go away.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

// Accept implements the `net.TCPListener#Accept()`.
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}
<commit_msg>docs: update comments in server.go<commit_after>package air

import (
	"crypto/tls"
	"net"
	"net/http"
	"time"
)

// server represents the HTTP server.
//
// It's embedded with `http.Server`.
type server struct {
	*http.Server

	air *Air
}

// newServer returns a pointer of a new instance of `server`.
func newServer(a *Air) *server {
	s := &server{
		Server: &http.Server{},
		air:    a,
	}
	s.Addr = s.air.Config.Address
	s.Handler = s
	s.ReadTimeout = s.air.Config.ReadTimeout
	s.WriteTimeout = s.air.Config.WriteTimeout
	return s
}

// start starts the HTTP server.
func (s *server) start() error {
	cl := s.air.Config.Listener
	if cl != nil {
		return s.Serve(cl)
	}

	ln, err := net.Listen("tcp", s.air.Config.Address)
	if err != nil {
		return err
	}

	ctcf := s.air.Config.TLSCertFile
	ctkf := s.air.Config.TLSKeyFile
	if ctcf != "" && ctkf != "" {
		tlscfg := &tls.Config{}
		if !s.air.Config.DisableHTTP2 {
			tlscfg.NextProtos = append(tlscfg.NextProtos, "h2")
		}
		tlscfg.Certificates = make([]tls.Certificate, 1)
		tlscfg.Certificates[0], err = tls.LoadX509KeyPair(ctcf, ctkf)
		if err != nil {
			return err
		}
		cl = tls.NewListener(
			tcpKeepAliveListener{ln.(*net.TCPListener)},
			tlscfg,
		)
	} else {
		cl = tcpKeepAliveListener{ln.(*net.TCPListener)}
	}

	return s.Serve(cl)
}

// stop stops the HTTP server.
func (s *server) stop() error {
	return s.air.Config.Listener.Close()
}

// ServeHTTP implements the `http.Handler`.
func (s *server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	c := contextPool.Get().(*Context)
	c.feed(rw, req)

	// Gases
	h := func(c *Context) error {
		method := c.Request.Method
		path := c.Request.URL.EscapedPath()
		s.air.router.route(method, path, c)
		h := c.Handler
		for i := len(s.air.gases) - 1; i >= 0; i-- {
			h = s.air.gases[i](h)
		}
		return h(c)
	}

	// Pregases
	for i := len(s.air.pregases) - 1; i >= 0; i-- {
		h = s.air.pregases[i](h)
	}

	// Execute chain
	if err := h(c); err != nil {
		s.air.HTTPErrorHandler(err, c)
	}

	c.reset()
	contextPool.Put(c)
}

// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted connections. It's used by
// ListenAndServe and ListenAndServeTLS so dead TCP connections (e.g. closing laptop mid-download)
// eventually go away.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

// Accept implements the `net.TCPListener#Accept()`.
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}
<|endoftext|>


<commit_before>package common

import (
	"context"
	"fmt"
	"log"
	"path/filepath"

	"github.com/hashicorp/packer-plugin-sdk/multistep"
	packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)

// This step attaches the boot ISO, cd_files iso, and guest additions to the
// virtual machine, if present.
type StepAttachISOs struct {
	AttachBootISO           bool
	ISOInterface            string
	GuestAdditionsMode      string
	GuestAdditionsInterface string
	diskUnmountCommands     map[string][]string
}

func (s *StepAttachISOs) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
	// Check whether there is anything to attach
	ui := state.Get("ui").(packersdk.Ui)

	ui.Say("Mounting ISOs...")
	diskMountMap := map[string]string{}
	s.diskUnmountCommands = map[string][]string{}
	// Track the bootable iso (only used in virtualbox-iso builder. )
	if s.AttachBootISO {
		isoPath := state.Get("iso_path").(string)
		diskMountMap["boot_iso"] = isoPath
	}

	// Determine if we even have a cd_files disk to attach
	if cdPathRaw, ok := state.GetOk("cd_path"); ok {
		cdFilesPath := cdPathRaw.(string)
		diskMountMap["cd_files"] = cdFilesPath
	}

	// Determine if we have guest additions to attach
	if s.GuestAdditionsMode != GuestAdditionsModeAttach {
		log.Println("Not attaching guest additions since we're uploading.")
	} else {
		// Get the guest additions path since we're doing it
		guestAdditionsPath := state.Get("guest_additions_path").(string)
		diskMountMap["guest_additions"] = guestAdditionsPath
	}

	if len(diskMountMap) == 0 {
		ui.Message("No ISOs to mount; continuing...")
		return multistep.ActionContinue
	}

	driver := state.Get("driver").(Driver)
	vmName := state.Get("vmName").(string)

	for diskCategory, isoPath := range diskMountMap {
		// If it's a symlink, resolve it to its target.
		resolvedIsoPath, err := filepath.EvalSymlinks(isoPath)
		if err != nil {
			err := fmt.Errorf("Error resolving symlink for ISO: %s", err)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}
		isoPath = resolvedIsoPath

		// We have three different potential isos we can attach, so let's
		// assign each one its own spot so they don't conflict.
		var controllerName, device, port string
		switch diskCategory {
		case "boot_iso":
			// figure out controller path
			controllerName = "IDE Controller"
			port = "0"
			device = "1"
			if s.ISOInterface == "sata" {
				controllerName = "SATA Controller"
				port = "1"
				device = "0"
			} else if s.ISOInterface == "virtio" {
				controllerName = "VirtIO Controller"
				port = "1"
				device = "0"
			}
			ui.Message("Mounting boot ISO...")
		case "guest_additions":
			controllerName = "IDE Controller"
			port = "1"
			device = "0"
			if s.GuestAdditionsInterface == "sata" {
				controllerName = "SATA Controller"
				port = "2"
				device = "0"
			} else if s.GuestAdditionsInterface == "virtio" {
				controllerName = "VirtIO Controller"
				port = "2"
				device = "0"
			}
			ui.Message("Mounting guest additions ISO...")
		case "cd_files":
			controllerName = "IDE Controller"
			port = "1"
			device = "1"
			if s.ISOInterface == "sata" {
				controllerName = "SATA Controller"
				port = "3"
				device = "0"
			} else if s.ISOInterface == "virtio" {
				controllerName = "VirtIO Controller"
				port = "3"
				device = "0"
         }
			ui.Message("Mounting cd_files ISO...")
		}

		// Attach the disk to the controller
		command := []string{
			"storageattach", vmName,
			"--storagectl", controllerName,
			"--port", port,
			"--device", device,
			"--type", "dvddrive",
			"--medium", isoPath,
		}
		if err := driver.VBoxManage(command...); err != nil {
			err := fmt.Errorf("Error attaching ISO: %s", err)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}

		// Track the disks we've mounted so we can remove them without having
		// to re-derive what was mounted where
		unmountCommand := []string{
			"storageattach", vmName,
			"--storagectl", controllerName,
			"--port", port,
			"--device", device,
			"--type", "dvddrive",
			"--medium", "none",
		}

		s.diskUnmountCommands[diskCategory] = unmountCommand
	}

	state.Put("disk_unmount_commands", s.diskUnmountCommands)

	return multistep.ActionContinue
}

func (s *StepAttachISOs) Cleanup(state multistep.StateBag) {
	if len(s.diskUnmountCommands) == 0 {
		return
	}

	driver := state.Get("driver").(Driver)
	_, ok := state.GetOk("detached_isos")

	if !ok {
		for _, command := range s.diskUnmountCommands {
			err := driver.VBoxManage(command...)
			if err != nil {
				log.Printf("error detaching iso: %s", err)
			}
		}
	}
}
<commit_msg>Fixed formatting.<commit_after>package common

import (
	"context"
	"fmt"
	"log"
	"path/filepath"

	"github.com/hashicorp/packer-plugin-sdk/multistep"
	packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)

// This step attaches the boot ISO, cd_files iso, and guest additions to the
// virtual machine, if present.
type StepAttachISOs struct {
	AttachBootISO           bool
	ISOInterface            string
	GuestAdditionsMode      string
	GuestAdditionsInterface string
	diskUnmountCommands     map[string][]string
}

func (s *StepAttachISOs) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
	// Check whether there is anything to attach
	ui := state.Get("ui").(packersdk.Ui)

	ui.Say("Mounting ISOs...")
	diskMountMap := map[string]string{}
	s.diskUnmountCommands = map[string][]string{}
	// Track the bootable iso (only used in virtualbox-iso builder. )
	if s.AttachBootISO {
		isoPath := state.Get("iso_path").(string)
		diskMountMap["boot_iso"] = isoPath
	}

	// Determine if we even have a cd_files disk to attach
	if cdPathRaw, ok := state.GetOk("cd_path"); ok {
		cdFilesPath := cdPathRaw.(string)
		diskMountMap["cd_files"] = cdFilesPath
	}

	// Determine if we have guest additions to attach
	if s.GuestAdditionsMode != GuestAdditionsModeAttach {
		log.Println("Not attaching guest additions since we're uploading.")
	} else {
		// Get the guest additions path since we're doing it
		guestAdditionsPath := state.Get("guest_additions_path").(string)
		diskMountMap["guest_additions"] = guestAdditionsPath
	}

	if len(diskMountMap) == 0 {
		ui.Message("No ISOs to mount; continuing...")
		return multistep.ActionContinue
	}

	driver := state.Get("driver").(Driver)
	vmName := state.Get("vmName").(string)

	for diskCategory, isoPath := range diskMountMap {
		// If it's a symlink, resolve it to its target.
		resolvedIsoPath, err := filepath.EvalSymlinks(isoPath)
		if err != nil {
			err := fmt.Errorf("Error resolving symlink for ISO: %s", err)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}
		isoPath = resolvedIsoPath

		// We have three different potential isos we can attach, so let's
		// assign each one its own spot so they don't conflict.
		var controllerName, device, port string
		switch diskCategory {
		case "boot_iso":
			// figure out controller path
			controllerName = "IDE Controller"
			port = "0"
			device = "1"
			if s.ISOInterface == "sata" {
				controllerName = "SATA Controller"
				port = "1"
				device = "0"
			} else if s.ISOInterface == "virtio" {
				controllerName = "VirtIO Controller"
				port = "1"
				device = "0"
			}
			ui.Message("Mounting boot ISO...")
		case "guest_additions":
			controllerName = "IDE Controller"
			port = "1"
			device = "0"
			if s.GuestAdditionsInterface == "sata" {
				controllerName = "SATA Controller"
				port = "2"
				device = "0"
			} else if s.GuestAdditionsInterface == "virtio" {
				controllerName = "VirtIO Controller"
				port = "2"
				device = "0"
			}
			ui.Message("Mounting guest additions ISO...")
		case "cd_files":
			controllerName = "IDE Controller"
			port = "1"
			device = "1"
			if s.ISOInterface == "sata" {
				controllerName = "SATA Controller"
				port = "3"
				device = "0"
			} else if s.ISOInterface == "virtio" {
				controllerName = "VirtIO Controller"
				port = "3"
				device = "0"
			}
			ui.Message("Mounting cd_files ISO...")
		}

		// Attach the disk to the controller
		command := []string{
			"storageattach", vmName,
			"--storagectl", controllerName,
			"--port", port,
			"--device", device,
			"--type", "dvddrive",
			"--medium", isoPath,
		}
		if err := driver.VBoxManage(command...); err != nil {
			err := fmt.Errorf("Error attaching ISO: %s", err)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}

		// Track the disks we've mounted so we can remove them without having
		// to re-derive what was mounted where
		unmountCommand := []string{
			"storageattach", vmName,
			"--storagectl", controllerName,
			"--port", port,
			"--device", device,
			"--type", "dvddrive",
			"--medium", "none",
		}

		s.diskUnmountCommands[diskCategory] = unmountCommand
	}

	state.Put("disk_unmount_commands", s.diskUnmountCommands)

	return multistep.ActionContinue
}

func (s *StepAttachISOs) Cleanup(state multistep.StateBag) {
	if len(s.diskUnmountCommands) == 0 {
		return
	}

	driver := state.Get("driver").(Driver)
	_, ok := state.GetOk("detached_isos")

	if !ok {
		for _, command := range s.diskUnmountCommands {
			err := driver.VBoxManage(command...)
			if err != nil {
				log.Printf("error detaching iso: %s", err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package xweb

import (
	"crypto/tls"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"runtime"
	runtimePprof "runtime/pprof"
	"strconv"
	"strings"
	"time"

	"github.com/coscms/xweb/httpsession"
	S "github.com/coscms/xweb/lib/manners"
	"github.com/coscms/xweb/log"
	"golang.org/x/net/netutil"
)

// ServerConfig is configuration for server objects.
type ServerConfig struct {
	Addr                   string
	Port                   int
	RecoverPanic           bool
	Profiler               bool
	EnableGzip             bool
	StaticExtensionsToGzip []string
	Url                    string
	UrlPrefix              string
	UrlSuffix              string
	StaticHtmlDir          string
	SessionTimeout         time.Duration
	MaxConnections         int
	UseSSL                 bool
	TlsConfig              *tls.Config
	Debug                  bool
	GracefulShutdown       bool
}

// Server represents a xweb server.
type Server struct {
	Config         *ServerConfig
	Apps           map[string]*App   //r["root"]
	App2Domain     map[string]string //r["root"]="www.coscms.com"
	Domain2App     map[string]string //r["www.coscms.com"]="root"
	AppsNamePath   map[string]string //r["root"]="/"
	Name           string
	SessionManager *httpsession.Manager
	RootApp        *App
	Logger         *log.Logger
	Env            map[string]interface{}
	Mux            *http.ServeMux

	//save the listener so it can be closed
	l net.Listener
}

func NewServer(name string) *Server {
	s := &Server{
		Config:       Config,
		Env:          map[string]interface{}{},
		Apps:         map[string]*App{},
		App2Domain:   map[string]string{},
		Domain2App:   map[string]string{},
		AppsNamePath: map[string]string{},
		Name:         name,
	}
	Servers[s.Name] = s

	s.SetLogger(log.New(os.Stdout, "", log.Ldefault()))

	app := NewApp("/", "root")
	s.AddApp(app)
	return s
}

func (s *Server) AddApp(a *App) {
	a.BasePath = strings.TrimRight(a.BasePath, "/") + "/"
	s.Apps[a.BasePath] = a

	if a.Name != "" {
		s.AppsNamePath[a.Name] = a.BasePath
	}

	a.Server = s
	a.Logger = s.Logger

	if a.BasePath == "/" {
		s.RootApp = a
	}
}

func (s *Server) AddAction(cs ...interface{}) {
	s.RootApp.AddAction(cs...)
}

func (s *Server) AutoAction(c ...interface{}) {
	s.RootApp.AutoAction(c...)
}

func (s *Server) AddRouter(url string, c interface{}) {
	s.RootApp.AddRouter(url, c)
}

func (s *Server) Assign(name string, varOrFun interface{}) {
	s.RootApp.Assign(name, varOrFun)
}

func (s *Server) MultiAssign(t *T) {
	s.RootApp.MultiAssign(t)
}

func (s *Server) AddFilter(filter Filter) {
	s.RootApp.AddFilter(filter)
}

func (s *Server) AddConfig(name string, value interface{}) {
	s.RootApp.SetConfig(name, value)
}

func (s *Server) SetConfig(name string, value interface{}) {
	s.RootApp.SetConfig(name, value)
}

func (s *Server) GetConfig(name string) interface{} {
	return s.RootApp.GetConfig(name)
}

func (s *Server) error(w http.ResponseWriter, status int, content string) error {
	return s.RootApp.error(w, status, content)
}

func (s *Server) initServer() {
	if s.Config == nil {
		s.Config = &ServerConfig{}
		s.Config.Profiler = true
	}

	for _, app := range s.Apps {
		app.initApp()
	}
}

// ServeHTTP is the interface method for Go's http server package
func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	s.Process(w, req)
}

type ServerInformation struct {
	*Server
	http.ResponseWriter
	*http.Request
}

// Process invokes the routing system for server s
// non-root app's route will override root app's if there is same path
func (s *Server) Process(w http.ResponseWriter, req *http.Request) {
	s.RootApp.RequestTime = time.Now()

	//set some default headers
	w.Header().Set("Server", "xweb v"+Version)
	w.Header().Set("Date", webTime(s.RootApp.RequestTime.UTC()))

	Event("ServerProcess", &ServerInformation{s, w, req}, func(result bool) {
		if !result {
			return
		}
		// static files, needed op
		if req.Method == "GET" || req.Method == "HEAD" {
			success, size := s.RootApp.TryServingFile(req.URL.Path, req, w)
			if success {
				s.RootApp.VisitedLog(req, 200, req.URL.Path, size)
				return
			}
			if req.URL.Path == "/favicon.ico" {
				s.RootApp.error(w, 404, "Page not found")
				s.RootApp.VisitedLog(req, 404, req.URL.Path, size)
				return
			}
		}

		if s.Config.UrlSuffix != "" && strings.HasSuffix(req.URL.Path, s.Config.UrlSuffix) {
			req.URL.Path = strings.TrimSuffix(req.URL.Path, s.Config.UrlSuffix)
		}
		if s.Config.UrlPrefix != "" && strings.HasPrefix(req.URL.Path, "/"+s.Config.UrlPrefix) {
			req.URL.Path = strings.TrimPrefix(req.URL.Path, "/"+s.Config.UrlPrefix)
		}
		if req.URL.Path[0] != '/' {
			req.URL.Path = "/" + req.URL.Path
		}
		if len(s.Domain2App) > 0 {
			var hostKey string
			if pos := strings.LastIndex(req.Host, ":"); pos <= 0 || req.Host[pos+1:] != "80" {
				hostKey = req.Host
			} else {
				hostKey = req.Host[0:pos]
			}
			var appName string
			if v, ok := s.Domain2App[hostKey]; ok {
				appName = v
			} else if v, ok := s.Domain2App["//"+hostKey]; ok {
				appName = v
			} else if v, ok := s.Domain2App[req.URL.Scheme+"://"+hostKey]; ok {
				appName = v
			}
			if appName != "" {
				if app := s.App(appName); app != nil {
					app.RequestTime = s.RootApp.RequestTime
					app.routeHandler(req, w)
					return
				}
			}
		}
		for _, app := range s.Apps {
			if app != s.RootApp && strings.HasPrefix(req.URL.Path, app.BasePath) {
				app.RequestTime = s.RootApp.RequestTime
				app.routeHandler(req, w)
				return
			}
		}
		s.RootApp.routeHandler(req, w)
	})
}

// Run starts the web application and serves HTTP requests for s
func (s *Server) Run(addr string) error {
	if s.Config.UseSSL {
		return s.RunTLS(addr, s.Config.TlsConfig)
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		s.Logger.Error("ListenAndServe:", err)
		return err
	}
	s.Logger.Infof("http server is listening %s", addr)
	return s.run(addr, l)
}

func (s *Server) run(addr string, l net.Listener) (err error) {
	if s.Config.Debug {
		println(`[xweb] Server "` + s.Name + `" has been launched.`)
	}
	addrs := strings.Split(addr, ":")
	s.Config.Addr = addrs[0]
	s.Config.Port, _ = strconv.Atoi(addrs[1])

	s.initServer()

	mux := http.NewServeMux()
	if s.Config.Profiler {
		mux.Handle("/debug/pprof", http.HandlerFunc(pprof.Index))
		mux.Handle("/debug/pprof/heap", pprof.Handler("heap"))
		mux.Handle("/debug/pprof/block", pprof.Handler("block"))
		mux.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
		mux.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))

		mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
		mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
		mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))

		mux.Handle("/debug/pprof/startcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			StartCPUProfile()
		}))
		mux.Handle("/debug/pprof/stopcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			StopCPUProfile()
		}))
		mux.Handle("/debug/pprof/memprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			runtime.GC()
			runtimePprof.WriteHeapProfile(rw)
		}))
		mux.Handle("/debug/pprof/gc", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			PrintGCSummary(rw)
		}))

	}
	s.Mux = mux
	Event("MuxHandle", s, func(result bool) {
		if result {
			mux.Handle("/", s)
		}
	})

	if s.Config.MaxConnections > 0 {
		l = netutil.LimitListener(l, s.Config.MaxConnections)
	}
	s.l = l
	if s.Config.GracefulShutdown {
		err = S.Serve(s.l, mux)
	} else {
		err = http.Serve(s.l, mux)
	}
	s.Close()
	if s.Config.Debug {
		println(`[xweb] Server "` + s.Name + `" has been closed.`)
	}
	return
}

// RunFcgi starts the web application and serves FastCGI requests for s.
func (s *Server) RunFcgi(addr string) {
	s.initServer()
	s.Logger.Infof("fcgi server is listening %s", addr)
	s.listenAndServeFcgi(addr)
}

// RunScgi starts the web application and serves SCGI requests for s.
func (s *Server) RunScgi(addr string) {
	s.initServer()
	s.Logger.Infof("scgi server is listening %s", addr)
	s.listenAndServeScgi(addr)
}

// RunTLS starts the web application and serves HTTPS requests for s.
func (s *Server) RunTLS(addr string, config *tls.Config) error {
	l, err := tls.Listen("tcp", addr, config)
	if err != nil {
		s.Logger.Errorf("Listen: %v", err)
		return err
	}
	s.Logger.Infof("https server is listening %s", addr)
	return s.run(addr, l)
}

// Close stops server s.
func (s *Server) Close() {
	for _, app := range s.Apps {
		app.Close()
	}
	if s.Config.GracefulShutdown {
		S.Close()
		s.l = nil
	}
	if s.l != nil {
		s.l.Close()
		s.l = nil
	}
}

func (s *Server) IsRunning() bool {
	return s.l != nil
}

// SetLogger sets the logger for server s
func (s *Server) SetLogger(logger *log.Logger) {
	s.Logger = logger
	s.Logger.SetPrefix("[" + s.Name + "] ")
	if s.RootApp != nil {
		s.RootApp.Logger = s.Logger
	}
}

func (s *Server) InitSession() {
	if s.SessionManager == nil {
		s.SessionManager = httpsession.Default()
	}
	if s.Config.SessionTimeout > time.Second {
		s.SessionManager.SetMaxAge(s.Config.SessionTimeout)
	}
	s.SessionManager.Run()
	if s.RootApp != nil {
		s.RootApp.SessionManager = s.SessionManager
	}
}

func (s *Server) SetTemplateDir(path string) {
	s.RootApp.SetTemplateDir(path)
}

func (s *Server) SetStaticDir(path string) {
	s.RootApp.SetStaticDir(path)
}

func (s *Server) App(name string) *App {
	path, ok := s.AppsNamePath[name]
	if ok {
		return s.Apps[path]
	}
	return nil
}
<commit_msg>improved NewServer<commit_after>package xweb

import (
	"crypto/tls"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"runtime"
	runtimePprof "runtime/pprof"
	"strconv"
	"strings"
	"time"

	"github.com/coscms/xweb/httpsession"
	S "github.com/coscms/xweb/lib/manners"
	"github.com/coscms/xweb/log"
	"golang.org/x/net/netutil"
)

// ServerConfig is configuration for server objects.
type ServerConfig struct {
	Addr                   string
	Port                   int
	RecoverPanic           bool
	Profiler               bool
	EnableGzip             bool
	StaticExtensionsToGzip []string
	Url                    string
	UrlPrefix              string
	UrlSuffix              string
	StaticHtmlDir          string
	SessionTimeout         time.Duration
	MaxConnections         int
	UseSSL                 bool
	TlsConfig              *tls.Config
	Debug                  bool
	GracefulShutdown       bool
}

// Server represents a xweb server.
type Server struct {
	Config         *ServerConfig
	Apps           map[string]*App   //r["root"]
	App2Domain     map[string]string //r["root"]="www.coscms.com"
	Domain2App     map[string]string //r["www.coscms.com"]="root"
	AppsNamePath   map[string]string //r["root"]="/"
	Name           string
	SessionManager *httpsession.Manager
	RootApp        *App
	Logger         *log.Logger
	Env            map[string]interface{}
	Mux            *http.ServeMux

	//save the listener so it can be closed
	l net.Listener
}

func NewServer(name string, args ...*ServerConfig) *Server {
	s := &Server{
		Env:          map[string]interface{}{},
		Apps:         map[string]*App{},
		App2Domain:   map[string]string{},
		Domain2App:   map[string]string{},
		AppsNamePath: map[string]string{},
		Name:         name,
	}
	if len(args) > 0 {
		s.Config = args[0]
	} else {
		s.Config = Config
	}
	Servers[s.Name] = s

	s.SetLogger(log.New(os.Stdout, "", log.Ldefault()))

	app := NewApp("/", "root")
	s.AddApp(app)
	return s
}

func (s *Server) AddApp(a *App) {
	a.BasePath = strings.TrimRight(a.BasePath, "/") + "/"
	s.Apps[a.BasePath] = a

	if a.Name != "" {
		s.AppsNamePath[a.Name] = a.BasePath
	}

	a.Server = s
	a.Logger = s.Logger

	if a.BasePath == "/" {
		s.RootApp = a
	}
}

func (s *Server) AddAction(cs ...interface{}) {
	s.RootApp.AddAction(cs...)
}

func (s *Server) AutoAction(c ...interface{}) {
	s.RootApp.AutoAction(c...)
}

func (s *Server) AddRouter(url string, c interface{}) {
	s.RootApp.AddRouter(url, c)
}

func (s *Server) Assign(name string, varOrFun interface{}) {
	s.RootApp.Assign(name, varOrFun)
}

func (s *Server) MultiAssign(t *T) {
	s.RootApp.MultiAssign(t)
}

func (s *Server) AddFilter(filter Filter) {
	s.RootApp.AddFilter(filter)
}

func (s *Server) AddConfig(name string, value interface{}) {
	s.RootApp.SetConfig(name, value)
}

func (s *Server) SetConfig(name string, value interface{}) {
	s.RootApp.SetConfig(name, value)
}

func (s *Server) GetConfig(name string) interface{} {
	return s.RootApp.GetConfig(name)
}

func (s *Server) error(w http.ResponseWriter, status int, content string) error {
	return s.RootApp.error(w, status, content)
}

func (s *Server) initServer() {
	if s.Config == nil {
		s.Config = &ServerConfig{}
		s.Config.Profiler = true
	}

	for _, app := range s.Apps {
		app.initApp()
	}
}

// ServeHTTP is the interface method for Go's http server package
func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	s.Process(w, req)
}

type ServerInformation struct {
	*Server
	http.ResponseWriter
	*http.Request
}

// Process invokes the routing system for server s
// non-root app's route will override root app's if there is same path
func (s *Server) Process(w http.ResponseWriter, req *http.Request) {
	s.RootApp.RequestTime = time.Now()

	//set some default headers
	w.Header().Set("Server", "xweb v"+Version)
	w.Header().Set("Date", webTime(s.RootApp.RequestTime.UTC()))

	Event("ServerProcess", &ServerInformation{s, w, req}, func(result bool) {
		if !result {
			return
		}
		// static files, needed op
		if req.Method == "GET" || req.Method == "HEAD" {
			success, size := s.RootApp.TryServingFile(req.URL.Path, req, w)
			if success {
				s.RootApp.VisitedLog(req, 200, req.URL.Path, size)
				return
			}
			if req.URL.Path == "/favicon.ico" {
				s.RootApp.error(w, 404, "Page not found")
				s.RootApp.VisitedLog(req, 404, req.URL.Path, size)
				return
			}
		}

		if s.Config.UrlSuffix != "" && strings.HasSuffix(req.URL.Path, s.Config.UrlSuffix) {
			req.URL.Path = strings.TrimSuffix(req.URL.Path, s.Config.UrlSuffix)
		}
		if s.Config.UrlPrefix != "" && strings.HasPrefix(req.URL.Path, "/"+s.Config.UrlPrefix) {
			req.URL.Path = strings.TrimPrefix(req.URL.Path, "/"+s.Config.UrlPrefix)
		}
		if req.URL.Path[0] != '/' {
			req.URL.Path = "/" + req.URL.Path
		}
		if len(s.Domain2App) > 0 {
			var hostKey string
			if pos := strings.LastIndex(req.Host, ":"); pos <= 0 || req.Host[pos+1:] != "80" {
				hostKey = req.Host
			} else {
				hostKey = req.Host[0:pos]
			}
			var appName string
			if v, ok := s.Domain2App[hostKey]; ok {
				appName = v
			} else if v, ok := s.Domain2App["//"+hostKey]; ok {
				appName = v
			} else if v, ok := s.Domain2App[req.URL.Scheme+"://"+hostKey]; ok {
				appName = v
			}
			if appName != "" {
				if app := s.App(appName); app != nil {
					app.RequestTime = s.RootApp.RequestTime
					app.routeHandler(req, w)
					return
				}
			}
		}
		for _, app := range s.Apps {
			if app != s.RootApp && strings.HasPrefix(req.URL.Path, app.BasePath) {
				app.RequestTime = s.RootApp.RequestTime
				app.routeHandler(req, w)
				return
			}
		}
		s.RootApp.routeHandler(req, w)
	})
}

// Run starts the web application and serves HTTP requests for s
func (s *Server) Run(addr string) error {
	if s.Config.UseSSL {
		return s.RunTLS(addr, s.Config.TlsConfig)
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		s.Logger.Error("ListenAndServe:", err)
		return err
	}
	s.Logger.Infof("http server is listening %s", addr)
	return s.run(addr, l)
}

func (s *Server) run(addr string, l net.Listener) (err error) {
	if s.Config.Debug {
		println(`[xweb] Server "` + s.Name + `" has been launched.`)
	}
	addrs := strings.Split(addr, ":")
	s.Config.Addr = addrs[0]
	s.Config.Port, _ = strconv.Atoi(addrs[1])

	s.initServer()

	mux := http.NewServeMux()
	if s.Config.Profiler {
		mux.Handle("/debug/pprof", http.HandlerFunc(pprof.Index))
		mux.Handle("/debug/pprof/heap", pprof.Handler("heap"))
		mux.Handle("/debug/pprof/block", pprof.Handler("block"))
		mux.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
		mux.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))

		mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
		mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
		mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))

		mux.Handle("/debug/pprof/startcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			StartCPUProfile()
		}))
		mux.Handle("/debug/pprof/stopcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			StopCPUProfile()
		}))
		mux.Handle("/debug/pprof/memprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			runtime.GC()
			runtimePprof.WriteHeapProfile(rw)
		}))
		mux.Handle("/debug/pprof/gc", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			PrintGCSummary(rw)
		}))

	}
	s.Mux = mux
	Event("MuxHandle", s, func(result bool) {
		if result {
			mux.Handle("/", s)
		}
	})

	if s.Config.MaxConnections > 0 {
		l = netutil.LimitListener(l, s.Config.MaxConnections)
	}
	s.l = l
	if s.Config.GracefulShutdown {
		err = S.Serve(s.l, mux)
	} else {
		err = http.Serve(s.l, mux)
	}
	s.Close()
	if s.Config.Debug {
		println(`[xweb] Server "` + s.Name + `" has been closed.`)
	}
	return
}

// RunFcgi starts the web application and serves FastCGI requests for s.
func (s *Server) RunFcgi(addr string) {
	s.initServer()
	s.Logger.Infof("fcgi server is listening %s", addr)
	s.listenAndServeFcgi(addr)
}

// RunScgi starts the web application and serves SCGI requests for s.
func (s *Server) RunScgi(addr string) {
	s.initServer()
	s.Logger.Infof("scgi server is listening %s", addr)
	s.listenAndServeScgi(addr)
}

// RunTLS starts the web application and serves HTTPS requests for s.
func (s *Server) RunTLS(addr string, config *tls.Config) error {
	l, err := tls.Listen("tcp", addr, config)
	if err != nil {
		s.Logger.Errorf("Listen: %v", err)
		return err
	}
	s.Logger.Infof("https server is listening %s", addr)
	return s.run(addr, l)
}

// Close stops server s.
func (s *Server) Close() {
	for _, app := range s.Apps {
		app.Close()
	}
	if s.Config.GracefulShutdown {
		S.Close()
		s.l = nil
	}
	if s.l != nil {
		s.l.Close()
		s.l = nil
	}
}

func (s *Server) IsRunning() bool {
	return s.l != nil
}

// SetLogger sets the logger for server s
func (s *Server) SetLogger(logger *log.Logger) {
	s.Logger = logger
	s.Logger.SetPrefix("[" + s.Name + "] ")
	if s.RootApp != nil {
		s.RootApp.Logger = s.Logger
	}
}

func (s *Server) InitSession() {
	if s.SessionManager == nil {
		s.SessionManager = httpsession.Default()
	}
	if s.Config.SessionTimeout > time.Second {
		s.SessionManager.SetMaxAge(s.Config.SessionTimeout)
	}
	s.SessionManager.Run()
	if s.RootApp != nil {
		s.RootApp.SessionManager = s.SessionManager
	}
}

func (s *Server) SetTemplateDir(path string) {
	s.RootApp.SetTemplateDir(path)
}

func (s *Server) SetStaticDir(path string) {
	s.RootApp.SetStaticDir(path)
}

func (s *Server) App(name string) *App {
	path, ok := s.AppsNamePath[name]
	if ok {
		return s.Apps[path]
	}
	return nil
}
<|endoftext|>


<commit_before>package tls

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
)

type keyAlgo func(d *schema.ResourceData) (interface{}, error)
type keyParser func([]byte) (interface{}, error)

var keyAlgos map[string]keyAlgo = map[string]keyAlgo{
	"RSA": func(d *schema.ResourceData) (interface{}, error) {
		rsaBits := d.Get("rsa_bits").(int)
		return rsa.GenerateKey(rand.Reader, rsaBits)
	},
	"ECDSA": func(d *schema.ResourceData) (interface{}, error) {
		curve := d.Get("ecdsa_curve").(string)
		switch curve {
		case "P224":
			return ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
		case "P256":
			return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
		case "P384":
			return ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
		case "P521":
			return ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
		default:
			return nil, fmt.Errorf("invalid ecdsa_curve; must be P224, P256, P384 or P521")
		}
	},
}

var keyParsers map[string]keyParser = map[string]keyParser{
	"RSA": func(der []byte) (interface{}, error) {
		return x509.ParsePKCS1PrivateKey(der)
	},
	"ECDSA": func(der []byte) (interface{}, error) {
		return x509.ParseECPrivateKey(der)
	},
}

func resourcePrivateKey() *schema.Resource {
	return &schema.Resource{
		Create: CreatePrivateKey,
		Delete: DeletePrivateKey,
		Read:   ReadPrivateKey,

		Schema: map[string]*schema.Schema{
			"algorithm": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "Name of the algorithm to use to generate the private key",
				ForceNew:    true,
			},

			"rsa_bits": &schema.Schema{
				Type:        schema.TypeInt,
				Optional:    true,
				Description: "Number of bits to use when generating an RSA key",
				ForceNew:    true,
				Default:     2048,
			},

			"ecdsa_curve": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "ECDSA curve to use when generating a key",
				ForceNew:    true,
				Default:     "P224",
			},

			"private_key_pem": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"public_key_pem": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func CreatePrivateKey(d *schema.ResourceData, meta interface{}) error {
	keyAlgoName := d.Get("algorithm").(string)
	var keyFunc keyAlgo
	var ok bool
	if keyFunc, ok = keyAlgos[keyAlgoName]; !ok {
		return fmt.Errorf("invalid key_algorithm %#v", keyAlgoName)
	}

	key, err := keyFunc(d)
	if err != nil {
		return err
	}

	var keyPemBlock *pem.Block
	switch k := key.(type) {
	case *rsa.PrivateKey:
		keyPemBlock = &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
	case *ecdsa.PrivateKey:
		b, err := x509.MarshalECPrivateKey(k)
		if err != nil {
			return fmt.Errorf("error encoding key to PEM: %s", err)
		}
		keyPemBlock = &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
	case *ecdsa.PublicKey:
		pubKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey(key))
		if err != nil {
			return fmt.Errorf("failed to marshal public key: %s", err)
		}
		pubKeyPemBlock := &pem.Block{Type: "EC PUBLIC KEY", Bytes: pubKeyBytes}
	default:
		return fmt.Errorf("unsupported private key type")
	}
	keyPem := string(pem.EncodeToMemory(keyPemBlock))

	d.SetId(hashForState(string((pubKeyBytes))))
	d.Set("private_key_pem", keyPem)

	return nil
}

func DeletePrivateKey(d *schema.ResourceData, meta interface{}) error {
	d.SetId("")
	return nil
}

func ReadPrivateKey(d *schema.ResourceData, meta interface{}) error {
	return nil
}

func publicKey(priv interface{}) interface{} {
	switch k := priv.(type) {
	case *rsa.PrivateKey:
		return &k.PublicKey
	case *ecdsa.PrivateKey:
		return &k.PublicKey
	default:
		return nil
	}
}
<commit_msg>Fixing a variable scope issue<commit_after>package tls

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
)

type keyAlgo func(d *schema.ResourceData) (interface{}, error)
type keyParser func([]byte) (interface{}, error)

var keyAlgos map[string]keyAlgo = map[string]keyAlgo{
	"RSA": func(d *schema.ResourceData) (interface{}, error) {
		rsaBits := d.Get("rsa_bits").(int)
		return rsa.GenerateKey(rand.Reader, rsaBits)
	},
	"ECDSA": func(d *schema.ResourceData) (interface{}, error) {
		curve := d.Get("ecdsa_curve").(string)
		switch curve {
		case "P224":
			return ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
		case "P256":
			return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
		case "P384":
			return ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
		case "P521":
			return ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
		default:
			return nil, fmt.Errorf("invalid ecdsa_curve; must be P224, P256, P384 or P521")
		}
	},
}

var keyParsers map[string]keyParser = map[string]keyParser{
	"RSA": func(der []byte) (interface{}, error) {
		return x509.ParsePKCS1PrivateKey(der)
	},
	"ECDSA": func(der []byte) (interface{}, error) {
		return x509.ParseECPrivateKey(der)
	},
}

func resourcePrivateKey() *schema.Resource {
	return &schema.Resource{
		Create: CreatePrivateKey,
		Delete: DeletePrivateKey,
		Read:   ReadPrivateKey,

		Schema: map[string]*schema.Schema{
			"algorithm": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "Name of the algorithm to use to generate the private key",
				ForceNew:    true,
			},

			"rsa_bits": &schema.Schema{
				Type:        schema.TypeInt,
				Optional:    true,
				Description: "Number of bits to use when generating an RSA key",
				ForceNew:    true,
				Default:     2048,
			},

			"ecdsa_curve": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "ECDSA curve to use when generating a key",
				ForceNew:    true,
				Default:     "P224",
			},

			"private_key_pem": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"public_key_pem": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func CreatePrivateKey(d *schema.ResourceData, meta interface{}) error {
	keyAlgoName := d.Get("algorithm").(string)
	var keyFunc keyAlgo
	var ok bool
	if keyFunc, ok = keyAlgos[keyAlgoName]; !ok {
		return fmt.Errorf("invalid key_algorithm %#v", keyAlgoName)
	}

	key, err := keyFunc(d)
	if err != nil {
		return err
	}

	var keyPemBlock *pem.Block
	switch k := key.(type) {
	case *rsa.PrivateKey:
		keyPemBlock = &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
	case *ecdsa.PrivateKey:
		b, err := x509.MarshalECPrivateKey(k)
		if err != nil {
			return fmt.Errorf("error encoding key to PEM: %s", err)
		}
		keyPemBlock = &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
	case *ecdsa.PublicKey:
		pubKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey(key))
		if err != nil {
			return fmt.Errorf("failed to marshal public key: %s", err)
		}
		pubKeyPemBlock := &pem.Block{Type: "EC PUBLIC KEY", Bytes: pubKeyBytes}
		d.SetId(hashForState(string((pubKeyBytes))))
	default:
		return fmt.Errorf("unsupported private key type")
	}
	keyPem := string(pem.EncodeToMemory(keyPemBlock))

	d.Set("private_key_pem", keyPem)

	return nil
}

func DeletePrivateKey(d *schema.ResourceData, meta interface{}) error {
	d.SetId("")
	return nil
}

func ReadPrivateKey(d *schema.ResourceData, meta interface{}) error {
	return nil
}

func publicKey(priv interface{}) interface{} {
	switch k := priv.(type) {
	case *rsa.PrivateKey:
		return &k.PublicKey
	case *ecdsa.PrivateKey:
		return &k.PublicKey
	default:
		return nil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gorilla/mux"
	"github.com/hectane/go-asyncserver"

	"encoding/json"
	"io/ioutil"
	"net/http"
	"strconv"
	"sync"
)

// Configuration for the server.
type ServerConfig struct {
	Addr string `json:"addr"`
	Root string `json:"root"`
}

// HTTP server providing the web interface and API.
type Server struct {
	mutex    sync.Mutex
	server   *server.AsyncServer
	channels []*Channel
}

// Write a JSON response.
func (s *Server) writeJSON(w http.ResponseWriter, i interface{}) {
	b, err := json.Marshal(i)
	if err != nil {
		http.Error(w, "internal server error", http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Length", strconv.Itoa(len(b)))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(b)
}

// Return a list of all channels.
func (s *Server) channelsHandler(w http.ResponseWriter, r *http.Request) {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	s.writeJSON(w, s.channels)
}

// Update a channel.
func (s *Server) channelHandler(w http.ResponseWriter, r *http.Request) {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	for _, channel := range s.channels {
		if channel.Config.Name == mux.Vars(r)["name"] {
			b, err := ioutil.ReadAll(r.Body)
			if err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
			}
			if err := channel.UnmarshalJSON(b); err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
			}
			s.writeJSON(w, channel)
			return
		}
	}
	http.Error(w, "channel not found", http.StatusNotFound)
}

// Create a new server instance.
func NewServer(config *ServerConfig, channels []*Channel) *Server {
	s := &Server{
		server:   server.New(config.Addr),
		channels: channels,
	}
	r := mux.NewRouter()
	r.Handle("/", http.FileServer(http.Dir(config.Root)))
	r.HandleFunc("/api/channels", s.channelsHandler).Methods("GET")
	r.HandleFunc("/api/channels/{name}", s.channelHandler).Methods("PUT")
	s.server.Handler = r
	return s
}

// Start the server.
func (s *Server) Start() error {
	return s.server.Start()
}

// Stop the server.
func (s *Server) Stop() {
	s.server.Stop()
}
<commit_msg>Fixed incorrect order in setting up mux handlers.<commit_after>package main

import (
	"github.com/gorilla/mux"
	"github.com/hectane/go-asyncserver"

	"encoding/json"
	"io/ioutil"
	"net/http"
	"strconv"
	"sync"
)

// Configuration for the server.
type ServerConfig struct {
	Addr string `json:"addr"`
	Root string `json:"root"`
}

// HTTP server providing the web interface and API.
type Server struct {
	mutex    sync.Mutex
	server   *server.AsyncServer
	channels []*Channel
}

// Write a JSON response.
func (s *Server) writeJSON(w http.ResponseWriter, i interface{}) {
	b, err := json.Marshal(i)
	if err != nil {
		http.Error(w, "internal server error", http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Length", strconv.Itoa(len(b)))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(b)
}

// Return a list of all channels.
func (s *Server) channelsHandler(w http.ResponseWriter, r *http.Request) {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	s.writeJSON(w, s.channels)
}

// Update a channel.
func (s *Server) channelHandler(w http.ResponseWriter, r *http.Request) {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	for _, channel := range s.channels {
		if channel.Config.Name == mux.Vars(r)["name"] {
			b, err := ioutil.ReadAll(r.Body)
			if err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
			}
			if err := channel.UnmarshalJSON(b); err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
			}
			s.writeJSON(w, channel)
			return
		}
	}
	http.Error(w, "channel not found", http.StatusNotFound)
}

// Create a new server instance.
func NewServer(config *ServerConfig, channels []*Channel) *Server {
	s := &Server{
		server:   server.New(config.Addr),
		channels: channels,
	}
	r := mux.NewRouter()
	r.HandleFunc("/api/channels", s.channelsHandler).Methods("GET")
	r.HandleFunc("/api/channels/{name}", s.channelHandler).Methods("PUT")
	r.PathPrefix("/").Handler(http.FileServer(http.Dir(config.Root)))
	s.server.Handler = r
	return s
}

// Start the server.
func (s *Server) Start() error {
	return s.server.Start()
}

// Stop the server.
func (s *Server) Stop() {
	s.server.Stop()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
)

var exampleJSON = []string{
	`{"Region":"eu-central-1","Bucket":"com.foo.bar"}`,
	`{"Up":true}`,
}

func Example() {
	for _, j := range exampleJSON {
		w, _ := jsondz.Unmarshal([]byte(j), caseWorker{}, complexSetupWorker{})
		fmt.Println(w.(Worker).Work("Hello World!"))
	}
	// Output:
	// Processed work Hello World! at eu-central-1-com.foo.bar region-bucket
	// HELLO WORLD!
}

// Worker interface
type Worker interface {
	Work(work string) string
}

type caseWorker struct {
	Up bool
}

func (u caseWorker) Work(work string) string {
	if u.Up {
		return strings.ToUpper(work)
	}
	return strings.ToLower(work)
}

type complexConfig struct {
	FooRegion string `json:"Region"`
	BarBucket string `json:"Bucket"`
}

type complexSetupWorker struct {
	c complexConfig
}

func (c complexSetupWorker) Work(work string) string {
	return fmt.Sprintf(
		"Processed work %s at %s-%s region-bucket",
		work, c.c.FooRegion,
		c.c.BarBucket,
	)
}

// New returns new instance of complexSetupWorker
func (c complexSetupWorker) New(conf complexConfig) *complexSetupWorker {
	// Do compex setup...
	return &complexSetupWorker{conf}
}
<commit_msg>Examples tuning...<commit_after>package jsondz

import (
	"fmt"
	"strings"
)

var exampleJSON = []string{
	`{"Region":"eu-central-1","Bucket":"com.foo.bar"}`,
	`{"Up":true}`,
}

func Example() {
	for _, j := range exampleJSON {
		w, _ := Unmarshal([]byte(j), caseWorker{}, complexSetupWorker{})
		fmt.Println(w.(Worker).Work("Hello World!"))
	}
	// Output:
	// Processed work Hello World! at eu-central-1-com.foo.bar region-bucket
	// HELLO WORLD!
}

// Worker interface
type Worker interface {
	Work(work string) string
}

type caseWorker struct {
	Up bool
}

func (u caseWorker) Work(work string) string {
	if u.Up {
		return strings.ToUpper(work)
	}
	return strings.ToLower(work)
}

type complexConfig struct {
	FooRegion string `json:"Region"`
	BarBucket string `json:"Bucket"`
}

type complexSetupWorker struct {
	c complexConfig
}

func (c complexSetupWorker) Work(work string) string {
	return fmt.Sprintf(
		"Processed work %s at %s-%s region-bucket",
		work, c.c.FooRegion,
		c.c.BarBucket,
	)
}

// New returns new instance of complexSetupWorker
func (c complexSetupWorker) New(conf complexConfig) *complexSetupWorker {
	// Do compex setup...
	return &complexSetupWorker{conf}
}
<|endoftext|>