github.com/go-email-validator/go-email-validator@v0.0.0-20230409163946-b8b9e6a0552e/pkg/ev/evsmtp/proxy.go (about)

     1  package evsmtp
     2  
     3  import (
     4  	"context"
     5  	"github.com/go-email-validator/go-email-validator/pkg/ev/evsmtp/smtpclient"
     6  	"github.com/tevino/abool"
     7  	"h12.io/socks"
     8  	"net"
     9  	"net/smtp"
    10  )
    11  
    12  // TCPConnection is tcp name
    13  const TCPConnection = "tcp"
    14  
    15  // DialFunc is function type to create smtpclient.SMTPClient
    16  type DialFunc func(ctx context.Context, addr, proxyURL string) (smtpclient.SMTPClient, error)
    17  
    18  var smtpNewClient = smtp.NewClient
    19  
    20  var directDial = DirectDial
    21  
    22  // DirectDial generates smtpclient.SMTPClient (smtp.Client)
    23  func DirectDial(ctx context.Context, addr, proxyURL string) (smtpclient.SMTPClient, error) {
    24  	d := net.Dialer{}
    25  	conn, err := d.DialContext(ctx, TCPConnection, addr)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	host, _, _ := net.SplitHostPort(addr)
    30  	return smtpNewClient(conn, host)
    31  }
    32  
    33  var h12ioDial = socks.Dial
    34  
    35  // H12IODial generates smtpclient.SMTPClient (smtp.Client) with proxy in socks.Dial
    36  func H12IODial(ctx context.Context, addr, proxyURL string) (smtpclient.SMTPClient, error) {
    37  	if proxyURL == "" {
    38  		return directDial(ctx, addr, proxyURL)
    39  	}
    40  	var c net.Conn
    41  	var client smtpclient.SMTPClient = nil
    42  	var err error
    43  	p := h12ioDial(proxyURL)
    44  
    45  	done := make(chan struct{}, 1)
    46  	needClose := abool.New()
    47  	go func() {
    48  		c, err = p("tcp", addr)
    49  		defer func() {
    50  			defer func() { close(done) }()
    51  
    52  			if needClose.IsSet() && c != nil {
    53  				c.Close()
    54  			}
    55  		}()
    56  
    57  		if err != nil {
    58  			return
    59  		}
    60  
    61  		host, _, _ := net.SplitHostPort(addr)
    62  		client, err = smtpNewClient(c, host)
    63  	}()
    64  
    65  	select {
    66  	case <-ctx.Done():
    67  		needClose.Set()
    68  		return nil, ctx.Err()
    69  	case <-done:
    70  		return client, err
    71  	}
    72  }