github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/ui/reverse_proxy.go (about) 1 /* 2 * Copyright (C) 2019 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package ui 19 20 import ( 21 "net" 22 "net/http" 23 "net/http/httputil" 24 "strconv" 25 "strings" 26 "time" 27 28 "github.com/mysteriumnetwork/node/tequilapi/tequil" 29 30 "github.com/gin-gonic/gin" 31 32 "github.com/mysteriumnetwork/node/core/auth" 33 ) 34 35 func buildTransport() *http.Transport { 36 return &http.Transport{ 37 Proxy: http.ProxyFromEnvironment, 38 DialContext: (&net.Dialer{ 39 Timeout: 20 * time.Second, 40 KeepAlive: 20 * time.Second, 41 }).DialContext, 42 MaxIdleConnsPerHost: 5, 43 IdleConnTimeout: 15, 44 } 45 } 46 47 func buildReverseProxy(tequilapiAddress string, tequilapiPort int) *httputil.ReverseProxy { 48 proxy := &httputil.ReverseProxy{ 49 Director: func(req *http.Request) { 50 req.URL.Scheme = "http" 51 req.URL.Host = tequilapiAddress + ":" + strconv.Itoa(tequilapiPort) 52 req.URL.Path = strings.Replace(req.URL.Path, tequil.TequilapiURLPrefix, "", 1) 53 req.URL.Path = strings.TrimRight(req.URL.Path, "/") 54 req.Header.Del("Origin") 55 req.Host = "127.0.0.1" + ":" + strconv.Itoa(tequilapiPort) 56 }, 57 ModifyResponse: func(res *http.Response) error { 58 // remove TequilAPI CORS headers 59 // these will be overwritten by Gin middleware 60 res.Header.Del("Access-Control-Allow-Origin") 61 res.Header.Del("Access-Control-Allow-Headers") 62 res.Header.Del("Access-Control-Allow-Methods") 63 return nil 64 }, 65 Transport: buildTransport(), 66 } 67 68 proxy.FlushInterval = 10 * time.Millisecond 69 70 return proxy 71 } 72 73 // ReverseTequilapiProxy proxies UIServer requests to the TequilAPI server 74 func ReverseTequilapiProxy(tequilapiAddress string, tequilapiPort int, authenticator jwtAuthenticator) gin.HandlerFunc { 75 proxy := buildReverseProxy(tequilapiAddress, tequilapiPort) 76 77 return func(c *gin.Context) { 78 // skip non reverse proxy routes 79 if !tequil.IsReverseProxyRoute(c.Request.URL.Path) { 80 return 81 } 82 83 // authenticate all but the authentication routes 84 if tequil.IsProtectedRoute(c.Request.URL.Path) { 85 authToken, err := auth.TokenFromContext(c) 86 if err != nil { 87 c.AbortWithStatus(http.StatusBadRequest) 88 return 89 } 90 91 if _, err := authenticator.ValidateToken(authToken); err != nil { 92 c.AbortWithStatus(http.StatusUnauthorized) 93 return 94 } 95 } 96 97 defer func() { 98 if err := recover(); err != nil { 99 if err == http.ErrAbortHandler { 100 // ignore streaming errors (SSE) 101 // there's nothing we can do about them 102 } else { 103 panic(err) 104 } 105 } 106 }() 107 108 proxy.ServeHTTP(c.Writer, c.Request) 109 } 110 }