<commit_before>package apiclient

import (
	"github.com/golang/protobuf/proto"

	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"path"
	"strconv"
	"strings"
)

type APIError struct {
	StatusCode int
}

func (e APIError) Error() string {
	return "web server error " + strconv.FormatInt(int64(e.StatusCode), 10)
}

type APIClient struct {
	// Base URL of the GRR AdminUI server, including the username and
	// password for HTTP Basic Authentication, e.g.
	// url.Parse("http://admin:admin@localhost:8000")
	BaseURL *url.URL
	// Client to use for web requests. If nil, it will be filled
	// on-demand with a copy http.DefaultClient to which a
	// "net/http/cookiejar".Jar has been added. The cookie jar is
	// needed for handling the csrf token mechanism.
	Client    *http.Client
	csrftoken string
}

func (c *APIClient) client() *http.Client {
	if c.Client == nil {
		c.Client = new(http.Client)
		*c.Client = *http.DefaultClient
		c.Client.Jar, _ = cookiejar.New(nil)
	}
	return c.Client
}

func (c *APIClient) getCSRFToken() string {
	if c.csrftoken == "" {
		rq, _ := http.NewRequest("GET", c.BaseURL.String(), nil)
		c.client().Do(rq)
		for _, cookie := range c.client().Jar.Cookies(c.BaseURL) {
			if cookie.Name == "csrftoken" {
				c.csrftoken = cookie.Value
				break
			}
		}
	}
	return c.csrftoken
}

// DoRequest performs the provided http.Request on the GRR server. It
// adds a CSRF token and skips over the ")]}'\n" XSS protection header
// if the GRR server returns a JSON document.
func (c *APIClient) DoRequest(rq *http.Request) (*http.Response, error) {
	rq.Header.Set("x-csrftoken", c.getCSRFToken())
	rs, err := c.client().Do(rq)
	if err != nil {
		return nil, err
	}
	if strings.HasPrefix(rs.Header.Get("Content-Type"), "application/json") {
		// skip XSS header<commit_msg>Explicitly set user, password in DoRequest<commit_after>package apiclient

import (
	"github.com/golang/protobuf/proto"

	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"path"
	"strconv"
	"strings"
)

type APIError struct {
	StatusCode int
}

func (e APIError) Error() string {
	return "web server error " + strconv.FormatInt(int64(e.StatusCode), 10)
}

type APIClient struct {
	// Base URL of the GRR AdminUI server, including the username and
	// password for HTTP Basic Authentication, e.g.
	// url.Parse("http://admin:admin@localhost:8000")
	BaseURL *url.URL
	// Client to use for web requests. If nil, it will be filled
	// on-demand with a copy http.DefaultClient to which a
	// "net/http/cookiejar".Jar has been added. The cookie jar is
	// needed for handling the csrf token mechanism.
	Client    *http.Client
	csrftoken string
}

func (c *APIClient) client() *http.Client {
	if c.Client == nil {
		c.Client = new(http.Client)
		*c.Client = *http.DefaultClient
		c.Client.Jar, _ = cookiejar.New(nil)
	}
	return c.Client
}

func (c *APIClient) getCSRFToken() string {
	if c.csrftoken == "" {
		rq, _ := http.NewRequest("GET", c.BaseURL.String(), nil)
		c.client().Do(rq)
		for _, cookie := range c.client().Jar.Cookies(c.BaseURL) {
			if cookie.Name == "csrftoken" {
				c.csrftoken = cookie.Value
				break
			}
		}
	}
	return c.csrftoken
}

// DoRequest performs the provided http.Request on the GRR server. It
// adds a CSRF token and skips over the ")]}'\n" XSS protection header
// if the GRR server returns a JSON document.
func (c *APIClient) DoRequest(rq *http.Request) (*http.Response, error) {
	rq.Header.Set("x-csrftoken", c.getCSRFToken())
	pass, _ := c.BaseURL.User.Password()
	rq.SetBasicAuth(c.BaseURL.User.Username(), pass)
	rs, err := c.client().Do(rq)
	if err != nil {
		return nil, err
	}
	if strings.HasPrefix(rs.Header.Get("Content-Type"), "application/json") {
		// skip XSS header
{'fraction_non_alphanumeric': 0.14243954291788466, 'fraction_numerical': 0.004251926654265214, 'mean_word_length': 3.5735115431348725, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, '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': '2165530', 'n_tokens_mistral': 1422, 'n_tokens_neox': 1383, 'n_words': 378}