<commit_before>package vm

import (
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"strings"

	"github.com/goby-lang/goby/vm/errors"
)

const (
	invalidSplatArgument    = "Splat arguments must be a string, got: %s on argument #%d"
	couldNotCompleteRequest = "Could not complete request, %s"
	non200Response          = "Non-200 response, %s (%d)"
)

var (
	httpRequestClass  *RClass
	httpResponseClass *RClass
	httpClientClass   *RClass
)

// Class methods --------------------------------------------------------
var builtinHTTPClassMethods = []*BuiltinMethodObject{
	{
		// Sends a GET request to the target and returns the HTTP response as a string. Will error on non-200 responses, for more control over http requests look at the `start` method.
		Name: "get",
		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
			arg0, ok := args[0].(*StringObject)
			if !ok {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 0, "String", args[0].Class().Name)
			}

			uri, err := url.Parse(arg0.value)

			if len(args) > 1 {
				var arr []string

				for i, v := range args[1:] {
					argn, ok := v.(*StringObject)
					if !ok {
						return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, invalidSplatArgument, v.Class().Name, i)
					}
					arr = append(arr, argn.value)
				}

				uri.Path = path.Join(arr...)
			}

			resp, err := http.Get(uri.String())
			if err != nil {
				return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
			}
			if resp.StatusCode != http.StatusOK {
				return t.vm.InitErrorObject(errors.HTTPError, sourceLine, non200Response, resp.Status, resp.StatusCode)
			}

			content, err := ioutil.ReadAll(resp.Body)
			resp.Body.Close()

			if err != nil {
				return t.vm.InitErrorObject(errors.InternalError, sourceLine, err.Error())
			}

			return t.vm.InitStringObject(string(content))

		},
	}, {
		// Sends a POST request to the target with type header and body. Returns the HTTP response as a string. Will error on non-200 responses, for more control over http requests look at the `start` method.
		Name: "post",
		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
			if len(args) != 3 {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 3, len(args))
			}

			arg0, ok := args[0].(*StringObject)
			if !ok {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 0, "String", args[0].Class().Name)
			}
			host := arg0.value

			arg1, ok := args[1].(*StringObject)
			if !ok {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 1, "String", args[0].Class().Name)
			}
			contentType := arg1.value

			arg2, ok := args[2].(*StringObject)
			if !ok {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 2, "String", args[0].Class().Name)
			}
			body := arg2.value

			resp, err := http.Post(host, contentType, strings.NewReader(body))
			if err != nil {
				return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
			}
			if resp.StatusCode != http.StatusOK {
				return t.vm.InitErrorObject(errors.HTTPError, sourceLine, non200Response, resp.Status, resp.StatusCode)
			}

			content, err := ioutil.ReadAll(resp.Body)
			resp.Body.Close()

			if err != nil {
				return t.vm.InitErrorObject(errors.InternalError, sourceLine, err.Error())
			}

			return t.vm.InitStringObject(string(content))

		},
	}, {
		// Sends a HEAD request to the target with type header and body. Returns the HTTP headers as a map[string]string. Will error on non-200 responses, for more control over http requests look at the `start` method.
		Name: "head",
		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
			arg0, ok := args[0].(*StringObject)
			if !ok {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 0, "String", args[0].Class().Name)
			}

			uri, err := url.Parse(arg0.value)

			if len(args) > 1 {
				var arr []string

				for i, v := range args[1:] {
					argn, ok := v.(*StringObject)
					if !ok {
						return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, invalidSplatArgument, v.Class().Name, i)
					}
					arr = append(arr, argn.value)<commit_msg>Fix unhandled err<commit_after>package vm

import (
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"strings"

	"github.com/goby-lang/goby/vm/errors"
)

const (
	invalidSplatArgument    = "Splat arguments must be a string, got: %s on argument #%d"
	couldNotCompleteRequest = "Could not complete request, %s"
	non200Response          = "Non-200 response, %s (%d)"
)

var (
	httpRequestClass  *RClass
	httpResponseClass *RClass
	httpClientClass   *RClass
)

// Class methods --------------------------------------------------------
var builtinHTTPClassMethods = []*BuiltinMethodObject{
	{
		// Sends a GET request to the target and returns the HTTP response as a string. Will error on non-200 responses, for more control over http requests look at the `start` method.
		Name: "get",
		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
			arg0, ok := args[0].(*StringObject)
			if !ok {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 0, "String", args[0].Class().Name)
			}

			uri, err := url.Parse(arg0.value)

			if len(args) > 1 {
				var arr []string

				for i, v := range args[1:] {
					argn, ok := v.(*StringObject)
					if !ok {
						return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, invalidSplatArgument, v.Class().Name, i)
					}
					arr = append(arr, argn.value)
				}

				uri.Path = path.Join(arr...)
			}

			resp, err := http.Get(uri.String())
			if err != nil {
				return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
			}
			if resp.StatusCode != http.StatusOK {
				return t.vm.InitErrorObject(errors.HTTPError, sourceLine, non200Response, resp.Status, resp.StatusCode)
			}

			content, err := ioutil.ReadAll(resp.Body)
			resp.Body.Close()

			if err != nil {
				return t.vm.InitErrorObject(errors.InternalError, sourceLine, err.Error())
			}

			return t.vm.InitStringObject(string(content))

		},
	}, {
		// Sends a POST request to the target with type header and body. Returns the HTTP response as a string. Will error on non-200 responses, for more control over http requests look at the `start` method.
		Name: "post",
		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
			if len(args) != 3 {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 3, len(args))
			}

			arg0, ok := args[0].(*StringObject)
			if !ok {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 0, "String", args[0].Class().Name)
			}
			host := arg0.value

			arg1, ok := args[1].(*StringObject)
			if !ok {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 1, "String", args[0].Class().Name)
			}
			contentType := arg1.value

			arg2, ok := args[2].(*StringObject)
			if !ok {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 2, "String", args[0].Class().Name)
			}
			body := arg2.value

			resp, err := http.Post(host, contentType, strings.NewReader(body))
			if err != nil {
				return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
			}
			if resp.StatusCode != http.StatusOK {
				return t.vm.InitErrorObject(errors.HTTPError, sourceLine, non200Response, resp.Status, resp.StatusCode)
			}

			content, err := ioutil.ReadAll(resp.Body)
			resp.Body.Close()

			if err != nil {
				return t.vm.InitErrorObject(errors.InternalError, sourceLine, err.Error())
			}

			return t.vm.InitStringObject(string(content))

		},
	}, {
		// Sends a HEAD request to the target with type header and body. Returns the HTTP headers as a map[string]string. Will error on non-200 responses, for more control over http requests look at the `start` method.
		Name: "head",
		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
			arg0, ok := args[0].(*StringObject)
			if !ok {
				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 0, "String", args[0].Class().Name)
			}

			uri, err := url.Parse(arg0.value)
			if err != nil {
				return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
			}

			if len(args) > 1 {
				var arr []string

				for i, v := range args[1:] {
					argn, ok := v.(*StringObject)
					if !ok {
						return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, invalidSplatArgument, v.Class().Name, i)
					}
					arr = append(arr, argn.value)
{'fraction_non_alphanumeric': 0.13973321670675706, 'fraction_numerical': 0.01137109118740433, 'mean_word_length': 3.4816266536011757, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, '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': '442244', 'n_tokens_mistral': 3428, 'n_tokens_neox': 2947, 'n_words': 787}