Repository: google/go-github
File: github/github.go (Go)

Code before:
}

// NewUploadRequest creates an upload request. A relative URL can be provided in
// urlStr, in which case it is resolved relative to the UploadURL of the Client.
// Relative URLs should always be specified without a preceding slash.
func (c *Client) NewUploadRequest(urlStr string, reader io.Reader, size int64, mediaType string, opts ...RequestOption) (*http.Request, error) {
	if !strings.HasSuffix(c.UploadURL.Path, "/") {
		return nil, fmt.Errorf("uploadURL must have a trailing slash, but %q does not", c.UploadURL)
	}
	u, err := c.UploadURL.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", u.String(), reader)
	if err != nil {
		return nil, err
	}

	req.ContentLength = size

	if mediaType == "" {
		mediaType = defaultMediaType
	}
	req.Header.Set("Content-Type", mediaType)
	req.Header.Set("Accept", mediaTypeV3)
	req.Header.Set("User-Agent", c.UserAgent)
	req.Header.Set(headerAPIVersion, defaultAPIVersion)

	for _, opt := range opts {
		opt(req)
	}

	return req, nil
}

// Response is a GitHub API response. This wraps the standard http.Response
// returned from GitHub and provides convenient access to things like
// pagination links.
type Response struct {
	*http.Response

	// These fields provide the page values for paginating through a set of
	// results. Any or all of these may be set to the zero value for
	// responses that are not part of a paginated set, or for which there
	// are no additional pages.
	//
	// These fields support what is called "offset pagination" and should
	// be used with the ListOptions struct.
	NextPage  int
	PrevPage  int

Review comment (suggestion):
This wrapper forces uploads onto the generic copy path in all builds and on all platforms. Could we limit this only to Windows, where the issue exists?

For Windows: wrap into `uploadRequestBodyReader`, for non-Windows use the original reader.

Code after:
}

// NewUploadRequest creates an upload request. A relative URL can be provided in
// urlStr, in which case it is resolved relative to the UploadURL of the Client.
// Relative URLs should always be specified without a preceding slash.
func (c *Client) NewUploadRequest(urlStr string, reader io.Reader, size int64, mediaType string, opts ...RequestOption) (*http.Request, error) {
	if !strings.HasSuffix(c.UploadURL.Path, "/") {
		return nil, fmt.Errorf("uploadURL must have a trailing slash, but %q does not", c.UploadURL)
	}
	u, err := c.UploadURL.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	requestBody := reader
	if reader != nil {
		// Wrap the provided reader so transport code does not observe concrete body types
		// (for example *os.File) and switch to platform-specific sendfile fast paths.
		//
		// Why this exists:
		// race-enabled test runs on Windows have surfaced data races in the sendfile path
		// while request read/write loops run concurrently. Hiding concrete type information
		// keeps uploads on the generic io.Reader copy path, which is race-stable and preserves
		// request semantics (same bytes, same headers, same content length).
		requestBody = uploadRequestBodyReader{Reader: reader}
	}

	req, err := http.NewRequest("POST", u.String(), requestBody)
	if err != nil {
		return nil, err
	}

	req.ContentLength = size

	if mediaType == "" {
		mediaType = defaultMediaType
	}
	req.Header.Set("Content-Type", mediaType)
	req.Header.Set("Accept", mediaTypeV3)
	req.Header.Set("User-Agent", c.UserAgent)
	req.Header.Set(headerAPIVersion, defaultAPIVersion)

	for _, opt := range opts {
		opt(req)
	}

	return req, nil
}

// uploadRequestBodyReader intentionally wraps an io.Reader to hide concrete reader types.
// See NewUploadRequest for why this prevents race-prone transport optimizations.