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  }