Initial commit

This commit is contained in:
Mester Gábor
2026-03-19 07:12:03 +01:00
commit 2dd6519168
25 changed files with 3645 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
package api
import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"strings"
"time"
"greq/internal/storage"
)
// RunPreScript executes rf.PreScript before sending the request.
// The script receives REQUEST_URL, REQUEST_METHOD, REQUEST_BODY as env vars.
// Lines of stdout matching "Key: Value" are returned as extra headers to merge
// into the request. A non-zero exit is treated as an error (request is aborted).
func RunPreScript(script string, rf storage.RequestFile, envs map[string]string) (map[string]string, error) {
if strings.TrimSpace(script) == "" {
return nil, nil
}
out, err := runScript(script, map[string]string{
"REQUEST_URL": ResolveVariables(rf.URL, envs),
"REQUEST_METHOD": rf.Method,
"REQUEST_BODY": rf.Body,
})
if err != nil {
return nil, fmt.Errorf("pre_script failed: %w\nOutput: %s", err, out)
}
headers := make(map[string]string)
for _, line := range strings.Split(out, "\n") {
line = strings.TrimSpace(line)
if k, v, ok := splitScriptHeader(line); ok {
headers[k] = v
}
}
return headers, nil
}
// RunTestScript executes the test_script field of a request using the Lua runner.
// See RunLuaTestScript for available globals and helper functions.
func RunTestScript(script string, resp *Response) ([]TestResult, error) {
return RunLuaTestScript(script, resp)
}
// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------
func runScript(script string, vars map[string]string) (string, error) {
f, err := os.CreateTemp("", "greq-script-*.sh")
if err != nil {
return "", err
}
defer os.Remove(f.Name())
if _, err := f.WriteString("#!/bin/sh\n" + script + "\n"); err != nil {
f.Close()
return "", err
}
f.Close()
if err := os.Chmod(f.Name(), 0o700); err != nil {
return "", err
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "sh", f.Name())
// Start with the current process env, then overlay our custom vars
// so the script has access to PATH, HOME, etc.
cmd.Env = os.Environ()
for k, v := range vars {
cmd.Env = append(cmd.Env, k+"="+v)
}
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
err = cmd.Run()
return out.String(), err
}
func splitScriptHeader(s string) (key, val string, ok bool) {
idx := strings.Index(s, ": ")
if idx < 1 {
return "", "", false
}
k := strings.TrimSpace(s[:idx])
v := strings.TrimSpace(s[idx+2:])
// Reject lines that look like script output, not headers
if strings.ContainsAny(k, " \t=/") {
return "", "", false
}
return k, v, true
}