// Copyright (c) 2025 Nikolai Papin // // This file is part of Easywish // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See // the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . package minioclient import ( "io" "net/http" "net/url" "time" "maps" "github.com/gin-gonic/gin" ) func setupGinEndpoint(router *gin.Engine) { s3group := router.Group("/s3") s3group.Any("/*path", func(c *gin.Context) { path := c.Param("path") minioURL := &url.URL{ Scheme: "http", Host: "minio:9000", // XXX: hardcoded minio host Path: path, RawQuery: c.Request.URL.RawQuery, } req, err := http.NewRequest(c.Request.Method, minioURL.String(), c.Request.Body); if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Failed to create request"}) return } req = req.WithContext(c.Request.Context()) maps.Copy(req.Header, c.Request.Header) delete(req.Header, "Host") client := &http.Client{ Timeout: 30 * time.Second, // XXX: magic number CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, } resp, err := client.Do(req); if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Failed to forward request"}) return } defer resp.Body.Close() for key, values := range resp.Header { for _, value := range values { c.Writer.Header().Add(key, value) } } c.Status(resp.StatusCode) _, err = io.Copy(c.Writer, resp.Body); if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Failed to copy response body"}) return } }) }