93 lines
2.3 KiB
Go
93 lines
2.3 KiB
Go
package shared
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gorilla/websocket"
|
|
)
|
|
|
|
var StandardWSUpgrader = websocket.Upgrader{
|
|
ReadBufferSize: 16 * 1024,
|
|
WriteBufferSize: 16 * 1024,
|
|
CheckOrigin: func(*http.Request) bool {
|
|
return true
|
|
},
|
|
}
|
|
|
|
func ApplyCORS(w http.ResponseWriter, r *http.Request, allowedOrigins []string) {
|
|
origin := strings.TrimSpace(r.Header.Get("Origin"))
|
|
if origin == "" || !OriginAllowed(origin, allowedOrigins) {
|
|
return
|
|
}
|
|
headers := w.Header()
|
|
headers.Set("Access-Control-Allow-Origin", origin)
|
|
headers.Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET")
|
|
headers.Set("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept")
|
|
headers.Set("Access-Control-Max-Age", "600")
|
|
headers.Add("Vary", "Origin")
|
|
headers.Add("Vary", "Access-Control-Request-Method")
|
|
headers.Add("Vary", "Access-Control-Request-Headers")
|
|
}
|
|
|
|
func OriginAllowed(origin string, allowedOrigins []string) bool {
|
|
origin = strings.TrimSpace(origin)
|
|
if origin == "" {
|
|
return true
|
|
}
|
|
if len(allowedOrigins) == 0 {
|
|
return true
|
|
}
|
|
for _, allowed := range allowedOrigins {
|
|
if strings.HasSuffix(allowed, ":*") {
|
|
if strings.HasPrefix(origin, strings.TrimSuffix(allowed, "*")) {
|
|
return true
|
|
}
|
|
continue
|
|
}
|
|
if origin == allowed {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func WriteJSONError(w http.ResponseWriter, requestID any, statusCode int, code int, message string) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(statusCode)
|
|
_ = json.NewEncoder(w).Encode(ErrorEnvelope(requestID, code, message))
|
|
}
|
|
|
|
func ParseAllowedOrigins(raw string) []string {
|
|
if raw == "" {
|
|
return nil
|
|
}
|
|
parts := strings.Split(raw, ",")
|
|
result := make([]string, 0, len(parts))
|
|
for _, part := range parts {
|
|
part = strings.TrimSpace(part)
|
|
if part == "" {
|
|
continue
|
|
}
|
|
result = append(result, part)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// NewHTTPClient returns an http.Client with a customized high-performance transport.
|
|
// It uses a significantly larger connection pool to prevent socket exhaustion and
|
|
// performance degradation when hitting the same backend hosts heavily.
|
|
func NewHTTPClient(timeout time.Duration) *http.Client {
|
|
t := http.DefaultTransport.(*http.Transport).Clone()
|
|
t.MaxIdleConns = 1000
|
|
t.MaxIdleConnsPerHost = 100
|
|
t.IdleConnTimeout = 90 * time.Second
|
|
|
|
return &http.Client{
|
|
Timeout: timeout,
|
|
Transport: t,
|
|
}
|
|
}
|