github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/integration/messagebus/glue/utils/utils.go (about)

     1  /*  Glue - Robust Go and Javascript Socket Library
     2   *  Copyright (C) 2015  Roland Singer <roland.singer[at]desertbit.com>
     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 utils provides utilities for the glue socket implementation.
    19  package utils
    20  
    21  import (
    22  	"crypto/rand"
    23  	"fmt"
    24  	"net/http"
    25  	"strconv"
    26  	"strings"
    27  )
    28  
    29  //#################//
    30  //### Constants ###//
    31  //#################//
    32  
    33  const (
    34  	delimiter = "&"
    35  )
    36  
    37  //########################//
    38  //### Public Functions ###//
    39  //########################//
    40  
    41  // RandomString generates a random string.
    42  func RandomString(n int) string {
    43  	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    44  	var bytes = make([]byte, n)
    45  	rand.Read(bytes)
    46  	for i, b := range bytes {
    47  		bytes[i] = alphanum[b%byte(len(alphanum))]
    48  	}
    49  	return string(bytes)
    50  }
    51  
    52  // UnmarshalValues splits two values from a single string.
    53  // This function is chainable to extract multiple values.
    54  func UnmarshalValues(data string) (first, second string, err error) {
    55  	// Find the delimiter.
    56  	pos := strings.Index(data, delimiter)
    57  	if pos < 0 {
    58  		err = fmt.Errorf("unmarshal values: no delimiter found: '%s'", data)
    59  		return
    60  	}
    61  
    62  	// Extract the value length integer of the first value.
    63  	l, err := strconv.Atoi(data[:pos])
    64  	if err != nil {
    65  		err = fmt.Errorf("invalid value length: '%s'", data[:pos])
    66  		return
    67  	}
    68  
    69  	// Remove the value length from the data string.
    70  	data = data[pos+1:]
    71  
    72  	// Validate the value length.
    73  	if l < 0 || l > len(data) {
    74  		err = fmt.Errorf("invalid value length: out of bounds: '%v'", l)
    75  		return
    76  	}
    77  
    78  	// Split the first value from the second.
    79  	first = data[:l]
    80  	second = data[l:]
    81  
    82  	return
    83  }
    84  
    85  // MarshalValues joins two values into a single string.
    86  // They can be decoded by the UnmarshalValues function.
    87  func MarshalValues(first, second string) string {
    88  	return strconv.Itoa(len(first)) + delimiter + first + second
    89  }
    90  
    91  // RemoteAddress returns the IP address of the request.
    92  // If the X-Forwarded-For or X-Real-Ip http headers are set, then
    93  // they are used to obtain the remote address.
    94  // The boolean is true, if the remote address is obtained using the
    95  // request RemoteAddr() method.
    96  func RemoteAddress(r *http.Request) (string, bool) {
    97  	hdr := r.Header
    98  
    99  	// Try to obtain the ip from the X-Forwarded-For header
   100  	ip := hdr.Get("X-Forwarded-For")
   101  	if ip != "" {
   102  		// X-Forwarded-For is potentially a list of addresses separated with ","
   103  		parts := strings.Split(ip, ",")
   104  		if len(parts) > 0 {
   105  			ip = strings.TrimSpace(parts[0])
   106  
   107  			if ip != "" {
   108  				return ip, false
   109  			}
   110  		}
   111  	}
   112  
   113  	// Try to obtain the ip from the X-Real-Ip header
   114  	ip = strings.TrimSpace(hdr.Get("X-Real-Ip"))
   115  	if ip != "" {
   116  		return ip, false
   117  	}
   118  
   119  	// Fallback to the request remote address
   120  	return RemovePortFromRemoteAddr(r.RemoteAddr), true
   121  }
   122  
   123  // RemovePortFromRemoteAddr removes the port if present from the remote address.
   124  func RemovePortFromRemoteAddr(remoteAddr string) string {
   125  	pos := strings.LastIndex(remoteAddr, ":")
   126  	if pos < 0 {
   127  		return remoteAddr
   128  	}
   129  
   130  	return remoteAddr[:pos]
   131  }