package main import ( "context" "log" "net/http" "strings" "time" "git.k6n.net/go-cart-actor/pkg/cart" "git.k6n.net/go-cart-actor/pkg/checkout" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" ) func getOriginalHost(r *http.Request) string { proxyHost := r.Header.Get("X-Forwarded-Host") if proxyHost != "" { return proxyHost } return r.Host } func getClientIp(r *http.Request) string { ip := r.Header.Get("X-Forwarded-For") if ip == "" { ip = r.RemoteAddr } return ip } func getCurrency(country string) string { if country == "no" { return "NOK" } return "SEK" } func getLocale(country string) string { if country == "no" { return "nb-no" } return "sv-se" } func getCountryFromHost(host string) string { if strings.Contains(strings.ToLower(host), "-no") { return "no" } if strings.Contains(strings.ToLower(host), "-se") { return "se" } return "" } func (a *CheckoutPoolServer) reserveInventory(ctx context.Context, grain *checkout.CheckoutGrain) error { if a.inventoryService != nil { inventoryRequests := getInventoryRequests(grain.CartState.Items) _, err := a.inventoryService.ReservationCheck(ctx, inventoryRequests...) if err != nil { logger.WarnContext(ctx, "placeorder inventory check failed") return err } } return nil } const checkoutCookieName = "checkoutid" func setCheckoutCookie(w http.ResponseWriter, checkoutId checkout.CheckoutId, tls bool) { http.SetCookie(w, &http.Cookie{ Name: checkoutCookieName, Value: checkoutId.String(), Secure: tls, HttpOnly: true, Path: "/", Expires: time.Now().AddDate(0, 0, 14), SameSite: http.SameSiteLaxMode, }) } func CookieCheckoutIdHandler(fn func(w http.ResponseWriter, r *http.Request, checkoutId checkout.CheckoutId) error) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { var id checkout.CheckoutId cookie, err := r.Cookie(checkoutCookieName) if err != nil || cookie.Value == "" { w.WriteHeader(http.StatusNotAcceptable) return } else { parsed, ok := cart.ParseCartId(cookie.Value) if !ok { w.WriteHeader(http.StatusNotAcceptable) return } else { id = parsed } } err = fn(w, r, id) if err != nil { log.Printf("Server error, not remote error: %v\n", err) w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) } } } func (s *CheckoutPoolServer) ProxyHandler(fn func(w http.ResponseWriter, r *http.Request, checkoutId checkout.CheckoutId) error) func(w http.ResponseWriter, r *http.Request, checkoutId checkout.CheckoutId) error { return func(w http.ResponseWriter, r *http.Request, checkoutId checkout.CheckoutId) error { if ownerHost, ok := s.OwnerHost(uint64(checkoutId)); ok { ctx, span := tracer.Start(r.Context(), "proxy") defer span.End() span.SetAttributes(attribute.String("checkoutid", checkoutId.String())) hostAttr := attribute.String("other host", ownerHost.Name()) span.SetAttributes(hostAttr) logger.InfoContext(ctx, "checkout proxyed", "result", ownerHost.Name()) proxyCalls.Add(ctx, 1, metric.WithAttributes(hostAttr)) handled, err := ownerHost.Proxy(uint64(checkoutId), w, r, nil) grainLookups.Inc() if err == nil && handled { return nil } } _, span := tracer.Start(r.Context(), "own") span.SetAttributes(attribute.String("checkoutid", checkoutId.String())) defer span.End() return fn(w, r, checkoutId) } }