<commit_before>package chef

import (
	"bytes"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"
)

// ChefVersion that we pretend to emulate
const ChefVersion = "11.12.0"

// Body wraps io.Reader and adds methods for calculating hashes and detecting content
type Body struct {
	io.Reader
}

// AuthConfig representing a client and a private key used for encryption
//  This is embedded in the Client type
type AuthConfig struct {
	PrivateKey *rsa.PrivateKey
	ClientName string
}

// Client is vessel for public methods used against the chef-server
type Client struct {
	Auth    *AuthConfig
	BaseURL *url.URL
	client  *http.Client

	ACLs         *ACLService
	Clients      *ApiClientService
	Cookbooks    *CookbookService
	DataBags     *DataBagService
	Environments *EnvironmentService
	Nodes        *NodeService
	Roles        *RoleService
	Sandboxes    *SandboxService
	Search       *SearchService
}

// Config contains the configuration options for a chef client. This is Used primarily in the NewClient() constructor in order to setup a proper client object
type Config struct {
	// This should be the user ID on the chef server
	Name string

	// This is the plain text private Key for the user
	Key string

	// BaseURL is the chef server URL used to connect too. Is using orgs you should include your org in the url
	BaseURL string

	// When set to false (default) this will enable SSL Cert Verification. If you need to disable Cert Verification set to true
	SkipSSL bool

	// Time to wait in seconds before giving up on a request to the server
	Timeout time.Duration
}

/*
An ErrorResponse reports one or more errors caused by an API request.
Thanks to https://github.com/google/go-github
*/
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
}

// Buffer creates a  byte.Buffer copy from a io.Reader resets read on reader to 0,0
func (body *Body) Buffer() *bytes.Buffer {
	var b bytes.Buffer
	if body.Reader == nil {
		return &b
	}

	b.ReadFrom(body.Reader)
	_, err := body.Reader.(io.Seeker).Seek(0, 0)
	if err != nil {
		log.Fatal(err)
	}
	return &b
}

// Hash calculates the body content hash
func (body *Body) Hash() (h string) {
	b := body.Buffer()
	// empty buffs should return a empty string
	if b.Len() == 0 {
		h = HashStr("")
	}
	h = HashStr(b.String())
	return
}

// ContentType returns the content-type string of Body as detected by http.DetectContentType()
func (body *Body) ContentType() string {
	if json.Unmarshal(body.Buffer().Bytes(), &struct{}{}) == nil {
		return "application/json"
	}
	return http.DetectContentType(body.Buffer().Bytes())
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode)
}

// NewClient is the client generator used to instantiate a client for talking to a chef-server
// It is a simple constructor for the Client struct intended as a easy interface for issuing
// signed requests
func NewClient(cfg *Config) (*Client, error) {
	pk, err := PrivateKeyFromString([]byte(cfg.Key))
	if err != nil {
		return nil, err
	}

	baseUrl, _ := url.Parse(cfg.BaseURL)

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: cfg.SkipSSL},
	}

	c := &Client{
		Auth: &AuthConfig{
			PrivateKey: pk,
			ClientName: cfg.Name,
		},
		client: &http.Client{
			Transport: tr,
			Timeout:   cfg.Timeout * time.Second,
		},
		BaseURL: baseUrl,
	}
	c.ACLs = &ACLService{client: c}
	c.Clients = &ApiClientService{client: c}
	c.Cookbooks = &CookbookService{client: c}
	c.DataBags = &DataBagService{client: c}
	c.Environments = &EnvironmentService{client: c}
	c.Nodes = &NodeService{client: c}
	c.Roles = &RoleService{client: c}
	c.Sandboxes = &SandboxService{client: c}
	c.Search = &SearchService{client: c}
	return c, nil
}

// magicRequestDecoder performs a request on an endpoint, and decodes the response into the passed in Type
func (c *Client) magicRequestDecoder(method, path string, body io.Reader, v interface{}) error {
	req, err := c.NewRequest(method, path, body)
	if err != nil {
		return err
	}

	debug("Request: %+v \n", req)
	res, err := c.Do(req, v)
	debug("Response: %+v \n", res)
	if err != nil {
		return err
	}
	return err
}

// NewRequest returns a signed request  suitable for the chef server
func (c *Client) NewRequest(method string, requestUrl string, body io.Reader) (*http.Request, error) {
	relativeUrl, err := url.Parse(requestUrl)
	if err != nil {
		return nil, err
	}<commit_msg>Close resp.Body when done reading from it.<commit_after>package chef

import (
	"bytes"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"
)

// ChefVersion that we pretend to emulate
const ChefVersion = "11.12.0"

// Body wraps io.Reader and adds methods for calculating hashes and detecting content
type Body struct {
	io.Reader
}

// AuthConfig representing a client and a private key used for encryption
//  This is embedded in the Client type
type AuthConfig struct {
	PrivateKey *rsa.PrivateKey
	ClientName string
}

// Client is vessel for public methods used against the chef-server
type Client struct {
	Auth    *AuthConfig
	BaseURL *url.URL
	client  *http.Client

	ACLs         *ACLService
	Clients      *ApiClientService
	Cookbooks    *CookbookService
	DataBags     *DataBagService
	Environments *EnvironmentService
	Nodes        *NodeService
	Roles        *RoleService
	Sandboxes    *SandboxService
	Search       *SearchService
}

// Config contains the configuration options for a chef client. This is Used primarily in the NewClient() constructor in order to setup a proper client object
type Config struct {
	// This should be the user ID on the chef server
	Name string

	// This is the plain text private Key for the user
	Key string

	// BaseURL is the chef server URL used to connect too. Is using orgs you should include your org in the url
	BaseURL string

	// When set to false (default) this will enable SSL Cert Verification. If you need to disable Cert Verification set to true
	SkipSSL bool

	// Time to wait in seconds before giving up on a request to the server
	Timeout time.Duration
}

/*
An ErrorResponse reports one or more errors caused by an API request.
Thanks to https://github.com/google/go-github
*/
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
}

// Buffer creates a  byte.Buffer copy from a io.Reader resets read on reader to 0,0
func (body *Body) Buffer() *bytes.Buffer {
	var b bytes.Buffer
	if body.Reader == nil {
		return &b
	}

	b.ReadFrom(body.Reader)
	_, err := body.Reader.(io.Seeker).Seek(0, 0)
	if err != nil {
		log.Fatal(err)
	}
	return &b
}

// Hash calculates the body content hash
func (body *Body) Hash() (h string) {
	b := body.Buffer()
	// empty buffs should return a empty string
	if b.Len() == 0 {
		h = HashStr("")
	}
	h = HashStr(b.String())
	return
}

// ContentType returns the content-type string of Body as detected by http.DetectContentType()
func (body *Body) ContentType() string {
	if json.Unmarshal(body.Buffer().Bytes(), &struct{}{}) == nil {
		return "application/json"
	}
	return http.DetectContentType(body.Buffer().Bytes())
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode)
}

// NewClient is the client generator used to instantiate a client for talking to a chef-server
// It is a simple constructor for the Client struct intended as a easy interface for issuing
// signed requests
func NewClient(cfg *Config) (*Client, error) {
	pk, err := PrivateKeyFromString([]byte(cfg.Key))
	if err != nil {
		return nil, err
	}

	baseUrl, _ := url.Parse(cfg.BaseURL)

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: cfg.SkipSSL},
	}

	c := &Client{
		Auth: &AuthConfig{
			PrivateKey: pk,
			ClientName: cfg.Name,
		},
		client: &http.Client{
			Transport: tr,
			Timeout:   cfg.Timeout * time.Second,
		},
		BaseURL: baseUrl,
	}
	c.ACLs = &ACLService{client: c}
	c.Clients = &ApiClientService{client: c}
	c.Cookbooks = &CookbookService{client: c}
	c.DataBags = &DataBagService{client: c}
	c.Environments = &EnvironmentService{client: c}
	c.Nodes = &NodeService{client: c}
	c.Roles = &RoleService{client: c}
	c.Sandboxes = &SandboxService{client: c}
	c.Search = &SearchService{client: c}
	return c, nil
}

// magicRequestDecoder performs a request on an endpoint, and decodes the response into the passed in Type
func (c *Client) magicRequestDecoder(method, path string, body io.Reader, v interface{}) error {
	req, err := c.NewRequest(method, path, body)
	if err != nil {
		return err
	}

	debug("Request: %+v \n", req)
	res, err := c.Do(req, v)
	if res != nil {
		defer res.Body.Close()
	}
	debug("Response: %+v \n", res)
	if err != nil {
		return err
	}
	return err
}

// NewRequest returns a signed request  suitable for the chef server
func (c *Client) NewRequest(method string, requestUrl string, body io.Reader) (*http.Request, error) {
	relativeUrl, err := url.Parse(requestUrl)
	if err != nil {
		return nil, err
	}
{'fraction_non_alphanumeric': 0.1079043721731639, 'fraction_numerical': 0.0027999138488046522, 'mean_word_length': 3.70704510897111, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5018970', 'n_tokens_mistral': 3097, 'n_tokens_neox': 2970, 'n_words': 1079}