utils.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. The MIT License (MIT)
  3. Copyright (c) 2014-2017 DutchCoders [https://github.com/dutchcoders/]
  4. Copyright (c) 2018-2020 Andrea Spacca.
  5. Copyright (c) 2020- Andrea Spacca and Stefan Benten.
  6. Permission is hereby granted, free of charge, to any person obtaining a copy
  7. of this software and associated documentation files (the "Software"), to deal
  8. in the Software without restriction, including without limitation the rights
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the Software is
  11. furnished to do so, subject to the following conditions:
  12. The above copyright notice and this permission notice shall be included in
  13. all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. THE SOFTWARE.
  21. */
  22. package server
  23. import (
  24. "math"
  25. "net/http"
  26. "net/mail"
  27. "strconv"
  28. "strings"
  29. "github.com/aws/aws-sdk-go/aws"
  30. "github.com/aws/aws-sdk-go/aws/credentials"
  31. "github.com/aws/aws-sdk-go/aws/session"
  32. "github.com/golang/gddo/httputil/header"
  33. )
  34. func getAwsSession(accessKey, secretKey, region, endpoint string, forcePathStyle bool) *session.Session {
  35. return session.Must(session.NewSession(&aws.Config{
  36. Region: aws.String(region),
  37. Endpoint: aws.String(endpoint),
  38. Credentials: credentials.NewStaticCredentials(accessKey, secretKey, ""),
  39. S3ForcePathStyle: aws.Bool(forcePathStyle),
  40. }))
  41. }
  42. func formatNumber(format string, s uint64) string {
  43. return RenderFloat(format, float64(s))
  44. }
  45. var renderFloatPrecisionMultipliers = [10]float64{
  46. 1,
  47. 10,
  48. 100,
  49. 1000,
  50. 10000,
  51. 100000,
  52. 1000000,
  53. 10000000,
  54. 100000000,
  55. 1000000000,
  56. }
  57. var renderFloatPrecisionRounders = [10]float64{
  58. 0.5,
  59. 0.05,
  60. 0.005,
  61. 0.0005,
  62. 0.00005,
  63. 0.000005,
  64. 0.0000005,
  65. 0.00000005,
  66. 0.000000005,
  67. 0.0000000005,
  68. }
  69. func RenderFloat(format string, n float64) string {
  70. // Special cases:
  71. // NaN = "NaN"
  72. // +Inf = "+Infinity"
  73. // -Inf = "-Infinity"
  74. if math.IsNaN(n) {
  75. return "NaN"
  76. }
  77. if n > math.MaxFloat64 {
  78. return "Infinity"
  79. }
  80. if n < -math.MaxFloat64 {
  81. return "-Infinity"
  82. }
  83. // default format
  84. precision := 2
  85. decimalStr := "."
  86. thousandStr := ","
  87. positiveStr := ""
  88. negativeStr := "-"
  89. if len(format) > 0 {
  90. // If there is an explicit format directive,
  91. // then default values are these:
  92. precision = 9
  93. thousandStr = ""
  94. // collect indices of meaningful formatting directives
  95. formatDirectiveChars := []rune(format)
  96. formatDirectiveIndices := make([]int, 0)
  97. for i, char := range formatDirectiveChars {
  98. if char != '#' && char != '0' {
  99. formatDirectiveIndices = append(formatDirectiveIndices, i)
  100. }
  101. }
  102. if len(formatDirectiveIndices) > 0 {
  103. // Directive at index 0:
  104. // Must be a '+'
  105. // Raise an error if not the case
  106. // index: 0123456789
  107. // +0.000,000
  108. // +000,000.0
  109. // +0000.00
  110. // +0000
  111. if formatDirectiveIndices[0] == 0 {
  112. if formatDirectiveChars[formatDirectiveIndices[0]] != '+' {
  113. panic("RenderFloat(): invalid positive sign directive")
  114. }
  115. positiveStr = "+"
  116. formatDirectiveIndices = formatDirectiveIndices[1:]
  117. }
  118. // Two directives:
  119. // First is thousands separator
  120. // Raise an error if not followed by 3-digit
  121. // 0123456789
  122. // 0.000,000
  123. // 000,000.00
  124. if len(formatDirectiveIndices) == 2 {
  125. if (formatDirectiveIndices[1] - formatDirectiveIndices[0]) != 4 {
  126. panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
  127. }
  128. thousandStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
  129. formatDirectiveIndices = formatDirectiveIndices[1:]
  130. }
  131. // One directive:
  132. // Directive is decimal separator
  133. // The number of digit-specifier following the separator indicates wanted precision
  134. // 0123456789
  135. // 0.00
  136. // 000,0000
  137. if len(formatDirectiveIndices) == 1 {
  138. decimalStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
  139. precision = len(formatDirectiveChars) - formatDirectiveIndices[0] - 1
  140. }
  141. }
  142. }
  143. // generate sign part
  144. var signStr string
  145. if n >= 0.000000001 {
  146. signStr = positiveStr
  147. } else if n <= -0.000000001 {
  148. signStr = negativeStr
  149. n = -n
  150. } else {
  151. signStr = ""
  152. n = 0.0
  153. }
  154. // split number into integer and fractional parts
  155. intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])
  156. // generate integer part string
  157. intStr := strconv.Itoa(int(intf))
  158. // add thousand separator if required
  159. if len(thousandStr) > 0 {
  160. for i := len(intStr); i > 3; {
  161. i -= 3
  162. intStr = intStr[:i] + thousandStr + intStr[i:]
  163. }
  164. }
  165. // no fractional part, we can leave now
  166. if precision == 0 {
  167. return signStr + intStr
  168. }
  169. // generate fractional part
  170. fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
  171. // may need padding
  172. if len(fracStr) < precision {
  173. fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
  174. }
  175. return signStr + intStr + decimalStr + fracStr
  176. }
  177. func RenderInteger(format string, n int) string {
  178. return RenderFloat(format, float64(n))
  179. }
  180. // Request.RemoteAddress contains port, which we want to remove i.e.:
  181. // "[::1]:58292" => "[::1]"
  182. func ipAddrFromRemoteAddr(s string) string {
  183. idx := strings.LastIndex(s, ":")
  184. if idx == -1 {
  185. return s
  186. }
  187. return s[:idx]
  188. }
  189. func getIPAddress(r *http.Request) string {
  190. hdr := r.Header
  191. hdrRealIP := hdr.Get("X-Real-Ip")
  192. hdrForwardedFor := hdr.Get("X-Forwarded-For")
  193. if hdrRealIP == "" && hdrForwardedFor == "" {
  194. return ipAddrFromRemoteAddr(r.RemoteAddr)
  195. }
  196. if hdrForwardedFor != "" {
  197. // X-Forwarded-For is potentially a list of addresses separated with ","
  198. parts := strings.Split(hdrForwardedFor, ",")
  199. for i, p := range parts {
  200. parts[i] = strings.TrimSpace(p)
  201. }
  202. // TODO: should return first non-local address
  203. return parts[0]
  204. }
  205. return hdrRealIP
  206. }
  207. func encodeRFC2047(s string) string {
  208. // use mail's rfc2047 to encode any string
  209. addr := mail.Address{
  210. Name: s,
  211. Address: "",
  212. }
  213. return strings.Trim(addr.String(), " <>")
  214. }
  215. func acceptsHTML(hdr http.Header) bool {
  216. actual := header.ParseAccept(hdr, "Accept")
  217. for _, s := range actual {
  218. if s.Value == "text/html" {
  219. return (true)
  220. }
  221. }
  222. return (false)
  223. }