### Example Submodule Updates Source: https://github.com/ooni/oohttp/blob/main/README.md Instructions for updating individual submodules within the example directory and running tests to ensure their functionality. ```bash cd example ``` ```bash go test -race ./... ``` -------------------------------- ### Integrating utls with net/http in Go Source: https://github.com/ooni/oohttp/blob/main/example/example-utls-with-dial/README.md This example demonstrates how to override the default TLS dialer in Go's net/http package to use the utls library. This allows for custom TLS client implementations, similar to how OONI utilizes this pattern. ```go package main import ( "crypto/tls" "fmt" "net" "net/http" "github.com/refraction-networking/utls" ) func main() { // Create a custom TLS client config using utls // This is a simplified example; a real implementation would configure specific client hello details. clientHelloId := utls.HelloRandom // Create a utls.Config utlsConfig := &utls.Config{ ServerName: "example.com", ClientHelloID: clientHelloId, InsecureSkipVerify: true // For demonstration purposes, do not use in production } // Create a utls.UConn from a standard net.Conn // In a real scenario, you'd get the net.Conn from a Dialer. // For this example, we'll simulate a connection. // Override the default TLS dialer in net/http customTransport := &http.Transport{ DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { // Get a standard net.Conn conn, err := net.Dial("tcp", addr) if err != nil { return nil, err } // Wrap the connection with utls // Note: You would typically use your utlsConfig here. // For simplicity, we're using a placeholder. // Replace utlsConfig with your actual configured utls.Config // Example: uconn := utls.UClient(conn, utlsConfig, utls.HelloRandom) uconn := utls.UClient(conn, utlsConfig, utls.HelloRandom) if uconn.Handshake() != nil { return nil, fmt.Errorf("utls handshake failed: %v", err) } return uconn, nil }, } client := &http.Client{Transport: customTransport} // Make an HTTP request using the custom client resp, err := client.Get("https://example.com") if err != nil { fmt.Printf("Error making request: %v\n", err) return } defer resp.Body.Close() fmt.Printf("Response Status: %s\n", resp.Status) // Process the response body here } ``` -------------------------------- ### UTLS Integration with net/http Source: https://github.com/ooni/oohttp/blob/main/example/example-utls/README.md This example demonstrates how to integrate the refraction-networking/utls library with Go's standard net/http package. It shows the strategy of overriding the TLSClientFactory to wrap new TCP connections with UTLS, enabling custom TLS client behavior. ```go package main import ( "crypto/tls" "fmt" "net" "net/http" "github.com/refraction-networking/utls" ) // UTLSClientFactory is a custom TLSClientFactory that wraps connections with UTLS. type UTLSClientFactory struct { // Add any specific UTLS configuration here if needed } // CreateTLSClient creates a new TLS client connection. func (f *UTLSClientFactory) CreateTLSClient(conn net.Conn, config *tls.Config) (net.Conn, error) { // Create a UTLS client hello with a specific browser fingerprint. // You can choose different fingerprints from utls.ClientHelloID. clientHello := utls.ClientHelloID{ Client: utls.Chrome, // Example: Use Chrome's TLS fingerprint Version: tls.VersionTLS13, CipherSuites: utls.AvailableCipherSuites(), Extensions: utls.DefaultClientHelloExtensions(), GetSessionTicket: true, } // Create a UTLS connection. utlsConn := utls.UClient(conn, &utls.Config{ ServerName: config.ServerName, InsecureSkipVerify: config.InsecureSkipVerify, RootCAs: config.RootCAs, Certificates: config.Certificates, ClientHello: &clientHello, }, utls.HelloRandom ) return utlsConn, nil } func main() { // Create a custom HTTP client that uses our UTLSClientFactory. httpClient := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ ServerName: "example.com", // Replace with the server name you want to connect to }, Proxy: http.ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).DialContext, TLSHandshakeTimeout: 10 * time.Second, // Override the TLSClientFactory here TLSClientFactory: &UTLSClientFactory{}, }, } // Make an HTTP request using the custom client. resp, err := httpClient.Get("https://example.com") // Replace with the URL you want to request if err != nil { fmt.Printf("Error making request: %v\n", err) return } defer resp.Body.Close() fmt.Printf("Status Code: %d\n", resp.StatusCode) // You can read from resp.Body here } ``` -------------------------------- ### Configure TLSClientFactory for Proxied Connections Source: https://github.com/ooni/oohttp/blob/main/example/example-proxy/README.md This snippet shows how to set up an oohttp.Transport instance, configure a SOCKS5 proxy, and specify the TLSClientFactory to use uTLS for proxied connections. It emphasizes that TLSClientFactory should not be changed while the transport is in use to prevent data races. ```go package main import ( "log" "net/http" "github.com/refraction-networking/utls" "github.com/oooni/oohttp" ) func main() { // Create a new oohttp.Transport instance transport := &oohttp.Transport{ // Configure a SOCKS5 proxy Proxy: http.ProxyURL(mustParseURL("socks5://localhost:1080")) } // Set the TLSClientFactory to use uTLS transport.TLSClientFactory = &utls.UClientHelloID{ // Specify the desired uTLS client hello configuration // For example, to emulate a Chrome browser: ClientHello: utls.HelloChrome_102, } // Create an HTTP client using the configured transport client := &http.Client{ Transport: transport, } // Now, any requests made with this client that go through the proxy // will use uTLS. // Example request (replace with your actual URL) resp, err := client.Get("https://example.com") if err != nil { log.Fatalf("Error making request: %v", err) } defer resp.Body.Close() log.Printf("Received response: %s", resp.Status) } // Helper function to parse URL, panics on error func mustParseURL(rawURL string) *url.URL { parsedURL, err := url.Parse(rawURL) if err != nil { panic(err) } return parsedURL } ``` -------------------------------- ### Using oohttp as a direct replacement for net/http Source: https://github.com/ooni/oohttp/blob/main/README.md This snippet demonstrates the simplest way to use the oohttp library by directly replacing the standard Go net/http import. This approach is suitable when your codebase does not have existing dependencies on the standard net/http package. ```Go import "github.com/ooni/oohttp" ``` -------------------------------- ### Build and Test Commands Source: https://github.com/ooni/oohttp/blob/main/README.md Standard Go commands to verify the project builds correctly and that all tests pass, including race condition detection. ```bash go build -v ./... ``` ```bash go test -race ./... ``` -------------------------------- ### Dependency Management Source: https://github.com/ooni/oohttp/blob/main/README.md Commands to update Go dependencies to their latest versions and tidy the module cache. ```bash go get -u -v ./... && go mod tidy ``` -------------------------------- ### uconn Adapter for utls.UConn Source: https://github.com/ooni/oohttp/blob/main/README.md An adapter struct 'uconn' that implements the TLSConn interface for utls.UConn. It includes methods to adapt ConnectionState and HandshakeContext from utls.UConn to the TLSConn interface. ```Go // uconn is an adapter from utls.UConn to TLSConn. type uconn struct { *utls.UConn } // ConnectionState implements TLSConn's ConnectionState. func (c *uconn) ConnectionState() tls.ConnectionState { ustate := c.UConn.ConnectionState() return tls.ConnectionState{ Version: ustate.Version, HandshakeComplete: ustate.HandshakeComplete, // // [...] // // You get the idea. You need to copy all fields. We // intentionally snip early here so we are not forced // to ensure this code is always up-to-date. } } // HandshakeContext implements TLSConn's HandshakeContext. func (c *uconn) HandshakeContext(ctx context.Context) error { errch := make(chan error, 1) go func() { errch <- c.UConn.Handshake() }() select { case err := <-errch: return err case <-ctx.Done(): return ctx.Err() } } ``` -------------------------------- ### Configuring oohttp Transport with TLSClientFactory Source: https://github.com/ooni/oohttp/blob/main/README.md Demonstrates how to set the TLSClientFactory field of an oohttp.Transport to use a custom factory, such as 'utlsFactory', for creating TLS connections. ```Go txp := &oohttp.Transport{ // ... TLSClientFactory: utlsFactory, } ``` -------------------------------- ### Update and Merge Script Source: https://github.com/ooni/oohttp/blob/main/README.md This snippet describes the process of updating the project by merging changes from an upstream repository and running a merge script. ```bash ./tools/merge.bash ``` -------------------------------- ### utlsFactory for Creating TLSConn Source: https://github.com/ooni/oohttp/blob/main/README.md A factory function 'utlsFactory' that creates a new uTLS connection implementing the oohttp.TLSConn interface. It configures utls.Config based on the provided tls.Config. ```Go // utlsFactory creates a new uTLS connection. func utlsFactory(conn net.Conn, config *tls.Config) oohttp.TLSConn { uConfig := &utls.Config{ RootCAs: config.RootCAs, NextProtos: config.NextProtos, ServerName: config.ServerName, InsecureSkipVerify: config.InsecureSkipVerify, DynamicRecordSizingDisabled: config.DynamicRecordSizingDisabled, } return &uconn{utls.UClient(conn, uConfig, utls.HelloFirefox_55)} } ``` -------------------------------- ### Codebase Consistency Checks Source: https://github.com/ooni/oohttp/blob/main/README.md These commands ensure the codebase adheres to specific coding standards, such as replacing direct usage of '*tls.Conn' with 'TLSConn' and 'tls.Client' with 'TLSClientFactory'. ```bash git grep -n '\*tls\.Conn' ``` ```bash git grep -n 'tls\.Client' ``` -------------------------------- ### StdlibTransport Adapter for net/http Compatibility Source: https://github.com/ooni/oohttp/blob/main/README.md This code defines the StdlibTransport struct, which acts as an adapter to make the oohttp Transport compatible with the standard net/http.Transport interface. It allows code that depends on net/http to use the oohttp library internally by implementing the http.RoundTripper interface. ```Go // StdlibTransport is an adapter for integrating net/http dependend code. // It looks like an http.RoundTripper but uses this fork internally. type StdlibTransport struct { *Transport } // RoundTrip implements the http.RoundTripper interface. func (txp *StdlibTransport) RoundTrip(stdReq *http.Request) (*http.Response, error) { // ... } ``` -------------------------------- ### TLSConn Interface Definition Source: https://github.com/ooni/oohttp/blob/main/README.md Defines the TLSConn interface, which represents a TLS connection compatible with *tls.Conn. It extends net.Conn and adds methods for ConnectionState, HandshakeContext, and NetConn. ```Go package tlsconn import ( "context" "crypto/tls" "net" ) // TLSConn is the interface representing a *tls.Conn compatible // connection, which could possibly be different from a *tls.Conn // as long as it implements the interface. You can use, for // example, refraction-networking/utls instead of the stdlib. type TLSConn interface { // net.Conn is the underlying interface net.Conn // ConnectionState returns the ConnectionState according // to the standard library. ConnectionState() tls.ConnectionState // HandshakeContext performs an TLS handshake bounded // in time by the given context. HandshakeContext(ctx context.Context) error // NetConn returns the underlying net.Conn NetConn() net.Conn } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.