generic_http.go 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // Generic HTTP transport for imgproxy
  2. package generichttp
  3. import (
  4. "crypto/tls"
  5. "fmt"
  6. "net"
  7. "net/http"
  8. "syscall"
  9. "time"
  10. "golang.org/x/net/http2"
  11. )
  12. func New(verifyNetworks bool, config *Config) (*http.Transport, error) {
  13. if err := config.Validate(); err != nil {
  14. return nil, err
  15. }
  16. dialer := &net.Dialer{
  17. Timeout: 30 * time.Second,
  18. KeepAlive: 30 * time.Second,
  19. DualStack: true,
  20. }
  21. if verifyNetworks {
  22. dialer.Control = func(network, address string, c syscall.RawConn) error {
  23. return verifySourceNetwork(address, config)
  24. }
  25. }
  26. transport := &http.Transport{
  27. Proxy: http.ProxyFromEnvironment,
  28. DialContext: dialer.DialContext,
  29. MaxIdleConns: 100,
  30. MaxIdleConnsPerHost: 100,
  31. IdleConnTimeout: time.Duration(config.ClientKeepAliveTimeout) * time.Second,
  32. TLSHandshakeTimeout: 10 * time.Second,
  33. ExpectContinueTimeout: 1 * time.Second,
  34. ForceAttemptHTTP2: false,
  35. DisableCompression: true,
  36. HTTP2: &http.HTTP2Config{
  37. MaxReceiveBufferPerStream: 128 * 1024,
  38. },
  39. }
  40. if config.ClientKeepAliveTimeout <= 0 {
  41. transport.MaxIdleConnsPerHost = -1
  42. transport.DisableKeepAlives = true
  43. }
  44. if config.IgnoreSslVerification {
  45. transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
  46. }
  47. transport2, err := http2.ConfigureTransports(transport)
  48. if err != nil {
  49. return nil, err
  50. }
  51. // TODO: Move this to transport.HTTP2 when https://go.dev/issue/67813 is closed
  52. transport2.MaxReadFrameSize = 16 * 1024
  53. transport2.PingTimeout = 5 * time.Second
  54. transport2.ReadIdleTimeout = time.Second
  55. return transport, nil
  56. }
  57. func verifySourceNetwork(addr string, config *Config) error {
  58. host, _, err := net.SplitHostPort(addr)
  59. if err != nil {
  60. host = addr
  61. }
  62. ip := net.ParseIP(host)
  63. if ip == nil {
  64. return newSourceAddressError(fmt.Sprintf("Invalid source address: %s", addr))
  65. }
  66. if !config.AllowLoopbackSourceAddresses && (ip.IsLoopback() || ip.IsUnspecified()) {
  67. return newSourceAddressError(fmt.Sprintf("Loopback source address is not allowed: %s", addr))
  68. }
  69. if !config.AllowLinkLocalSourceAddresses && (ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast()) {
  70. return newSourceAddressError(fmt.Sprintf("Link-local source address is not allowed: %s", addr))
  71. }
  72. if !config.AllowPrivateSourceAddresses && ip.IsPrivate() {
  73. return newSourceAddressError(fmt.Sprintf("Private source address is not allowed: %s", addr))
  74. }
  75. return nil
  76. }