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 }