You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: http.go
    path of file: ./repos/zeebe/clients/go/vendor/github.com/testcontainers/testcontainers-go/wait
    
    the code of the file until where you have to start completion: package wait

import (
	"bytes"
	"context"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net"
	"ne
    
func (ws *HTTPStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
	timeout := defaultStartupTimeout()
	if ws.timeout != nil {
		timeout = *ws.timeout
	}

	ctx, cancel := context.WithTimeout(ctx, timeout)
	defer cancel()

	ipAddress, err := target.Host(ctx)
	if err != nil {
		return err
	}
	// to avoid ipv6 docker bugs https://github.com/moby/moby/issues/42442 https://github.com/moby/moby/issues/42375
	if ws.ForceIPv4LocalHost {
		ipAddress = strings.Replace(ipAddress, "localhost", "127.0.0.1", 1)
	}

	var mappedPort nat.Port
	if ws.Port == "" {
		var err error
		var ports nat.PortMap
		// we wait one polling interval before we grab the ports otherwise they might not be bound yet on startup
		for err != nil || ports == nil {
			select {
			case <-ctx.Done():
				return fmt.Errorf("%w: %w", ctx.Err(), err)
			case <-time.After(ws.PollInterval):
				if err := checkTarget(ctx, target); err != nil {
					return err
				}

				ports, err = target.Ports(ctx)
			}
		}

		for k, bindings := range ports {
			if len(bindings) == 0 || k.Proto() != "tcp" {
				continue
			}
			mappedPort, _ = nat.NewPort(k.Proto(), bindings[0].HostPort)
			break
		}

		if mappedPort == "" {
			return errors.New("No exposed tcp ports or mapped ports - cannot wait for status")
		}
	} else {
		mappedPort, err = target.MappedPort(ctx, ws.Port)

		for mappedPort == "" {
			select {
			case <-ctx.Done():
				return fmt.Errorf("%w: %w", ctx.Err(), err)
			case <-time.After(ws.PollInterval):
				if err := checkTarget(ctx, target); err != nil {
					return err
				}

				mappedPort, err = target.MappedPort(ctx, ws.Port)
			}
		}

		if mappedPort.Proto() != "tcp" {
			return errors.New("Cannot use HTTP client on non-TCP ports")
		}
	}

	switch ws.Method {
	case http.MethodGet, http.MethodHead, http.MethodPost,
		http.MethodPut, http.MethodPatch, http.MethodDelete,
		http.MethodConnect, http.MethodOptions, http.MethodTrace:
	default:
		if ws.Method != "" {
			return fmt.Errorf("invalid http method %q", ws.Method)
		}
		ws.Method = http.MethodGet
	}

	tripper := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			Timeout:   time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).DialContext,
		ForceAttemptHTTP2:     true,
		MaxIdleConns:          100,
		IdleConnTimeout:       90 * time.Second,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
		TLSClientConfig:       ws.TLSConfig,
	}

	var proto string
	if ws.UseTLS {
		proto = "https"
		if ws.AllowInsecure {
			if ws.TLSConfig == nil {
				tripper.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
			} else {
				ws.TLSConfig.InsecureSkipVerify = true
			}
		}
	} else {
		proto = "http"
	}

	client := http.Client{Transport: tripper, Timeout: time.Second}
	address := net.JoinHostPort(ipAddress, strconv.Itoa(mappedPort.Int()))

	endpoint := url.URL{
		Scheme: proto,
		Host:   address,
		Path:   ws.Path,
	}

	if ws.UserInfo != nil {
		endpoint.User = ws.UserInfo
	}

	// cache the body into a byte-slice so that it can be iterated over multiple times
	var body []byte
	if ws.Body != nil {
		body, err = io.ReadAll(ws.Body)
		if err != nil {
			return err
		}
	}

	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-time.After(ws.PollInterval):
			if err := checkTarget(ctx, target); err != nil {
				return err
			}
			req, err := http.NewRequestWithContext(ctx, ws.Method, endpoint.String(), bytes.NewReader(body))
			if err != nil {
				return err
			}
			resp, err := client.Do(req)
			if err != nil {
				continue
			}
			if ws.StatusCodeMatcher != nil && !ws.StatusCodeMatcher(resp.StatusCode) {
				_ = resp.Body.Close()
				continue
			}
			if ws.ResponseMatcher != nil && !ws.ResponseMatcher(resp.Body) {
				_ = resp.Body.Close()
				continue
			}
			if err := resp.Body.Close(); err != nil {
				continue
			}
			return nil
		}
	}
}