Skip to content

Instantly share code, notes, and snippets.

@acoshift
Created February 19, 2019 16:23
Show Gist options
  • Save acoshift/cb5a28c6586f35e0e3395c80dca91303 to your computer and use it in GitHub Desktop.
Save acoshift/cb5a28c6586f35e0e3395c80dca91303 to your computer and use it in GitHub Desktop.
Example how to use sync.Once in Golang
package main
import (
"fmt"
"net/http"
"strconv"
"strings"
"sync"
"time"
)
func main() {
http.ListenAndServe(":8080", &CORS{
Handler: http.HandlerFunc(hello),
AllowAllOrigins: true,
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE"},
AllowHeaders: []string{"Content-Type", "Authorization"},
ExposeHeaders: []string{"X-Request-Id"},
MaxAge: time.Hour,
})
}
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello")
}
type CORS struct {
Handler http.Handler
AllowAllOrigins bool
AllowOrigins []string
AllowMethods []string
AllowHeaders []string
AllowCredentials bool
ExposeHeaders []string
MaxAge time.Duration
// computed
allowOrigins map[string]struct{}
allowMethods string
allowHeaders string
exposeHeaders string
maxAge string
once sync.Once
}
func (c *CORS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c.once.Do(func() {
if c.AllowAllOrigins && c.AllowCredentials {
panic("cors: misconfigured allow all origins and credentials")
}
c.allowMethods = strings.Join(c.AllowMethods, ",")
c.allowHeaders = strings.Join(c.AllowHeaders, ",")
c.exposeHeaders = strings.Join(c.ExposeHeaders, ",")
c.maxAge = ""
if c.MaxAge > time.Duration(0) {
c.maxAge = strconv.FormatInt(int64(c.MaxAge/time.Second), 10)
}
c.allowOrigins = make(map[string]struct{})
for _, v := range c.AllowOrigins {
c.allowOrigins[v] = struct{}{}
}
})
if origin := r.Header.Get("Origin"); origin != "" {
h := w.Header()
if c.AllowAllOrigins {
h.Set("Access-Control-Allow-Origin", "*")
} else if _, ok := c.allowOrigins[origin]; ok {
h.Set("Access-Control-Allow-Origin", origin)
} else {
w.WriteHeader(http.StatusForbidden)
return
}
if c.AllowCredentials {
h.Set("Access-Control-Allow-Credentials", "true")
}
if r.Method == http.MethodOptions {
if c.allowMethods != "" {
h.Set("Access-Control-Allow-Methods", c.allowMethods)
}
if c.allowHeaders != "" {
h.Set("Access-Control-Allow-Headers", c.allowHeaders)
}
if c.maxAge != "" {
h.Set("Access-Control-Max-Age", c.maxAge)
}
if !c.AllowAllOrigins {
h.Add("Vary", "Origin")
}
h.Add("Vary", "Access-Control-Request-Method")
h.Add("Vary", "Access-Control-Request-Headers")
w.WriteHeader(http.StatusNoContent)
return
}
if c.exposeHeaders != "" {
h.Set("Access-Control-Expose-Headers", c.exposeHeaders)
}
if !c.AllowAllOrigins {
h.Set("Vary", "Origin")
}
}
c.Handler.ServeHTTP(w, r)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment