feat(script): replace followRedirects with maxRedirects http option

This commit is contained in:
aykhans committed 2026-09-20 23:18:21 +04:00
1 parent 8b437b487c
commit 529420ee5a
4 files changed
+66 -33

No files matched your search

+3 -6
View File
@@ -11,9 +11,6 @@ import (
"go.aykhans.me/sarin/internal/types" "go.aykhans.me/sarin/internal/types"
) )
// scriptHTTPMaxRedirects is the redirect limit when followRedirects is set.
const scriptHTTPMaxRedirects = 10
// scriptHTTPDefaultTimeout is the default timeout for script requests, independent of -T. // scriptHTTPDefaultTimeout is the default timeout for script requests, independent of -T.
const scriptHTTPDefaultTimeout = 30 * time.Second const scriptHTTPDefaultTimeout = 30 * time.Second
@@ -65,7 +62,7 @@ func newScriptHTTPClient(dialFunc fasthttp.DialFunc, defaultTimeout time.Duratio
} }
} }
// Do sends the request. With followRedirects the timeout applies to each hop. // Do sends the request. With maxRedirects the timeout applies to each hop.
// It can return the following errors: // It can return the following errors:
// - types.ScriptHTTPRequestError // - types.ScriptHTTPRequestError
func (c *scriptHTTPClient) Do(r *script.HTTPRequest) (*script.HTTPResponse, error) { func (c *scriptHTTPClient) Do(r *script.HTTPRequest) (*script.HTTPResponse, error) {
@@ -116,8 +113,8 @@ func (c *scriptHTTPClient) Do(r *script.HTTPRequest) (*script.HTTPResponse, erro
} }
req.SetTimeout(timeout) req.SetTimeout(timeout)
if r.FollowRedirects { if r.MaxRedirects > 0 {
err = client.DoRedirects(req, resp, scriptHTTPMaxRedirects) err = client.DoRedirects(req, resp, r.MaxRedirects)
} else { } else {
err = client.Do(req, resp) err = client.Do(req, resp)
} }
+32 -17
View File
@@ -1,7 +1,9 @@
package script package script
import ( import (
"math"
"net/http" "net/http"
"strconv"
"strings" "strings"
"time" "time"
@@ -10,15 +12,15 @@ import (
// HTTPRequest is a request made by a script through the http.* functions. // HTTPRequest is a request made by a script through the http.* functions.
type HTTPRequest struct { type HTTPRequest struct {
Method string Method string
URL string URL string
Headers map[string][]string Headers map[string][]string
Params map[string][]string Params map[string][]string
Cookies map[string][]string Cookies map[string][]string
Body string Body string
Timeout time.Duration // zero means the doer's default timeout Timeout time.Duration // zero means the doer's default timeout
Insecure bool Insecure bool
FollowRedirects bool MaxRedirects int
} }
// HTTPResponse is the response returned to a script by the http.* functions. // HTTPResponse is the response returned to a script by the http.* functions.
@@ -63,14 +65,14 @@ const httpDefaultMethod = http.MethodGet
// Option keys accepted by the http function. // Option keys accepted by the http function.
const ( const (
httpOptionMethod = "method" httpOptionMethod = "method"
httpOptionHeaders = "headers" httpOptionHeaders = "headers"
httpOptionParams = "params" httpOptionParams = "params"
httpOptionCookies = "cookies" httpOptionCookies = "cookies"
httpOptionBody = "body" httpOptionBody = "body"
httpOptionTimeout = "timeout" httpOptionTimeout = "timeout"
httpOptionInsecure = "insecure" httpOptionInsecure = "insecure"
httpOptionFollowRedirects = "followRedirects" httpOptionMaxRedirects = "maxRedirects"
) )
// httpBridge connects http to the doer. Calls only work while transform runs. // httpBridge connects http to the doer. Calls only work while transform runs.
@@ -97,6 +99,19 @@ func (b *httpBridge) do(req *HTTPRequest) (*HTTPResponse, error) {
return b.doer.Do(req) return b.doer.Do(req)
} }
// parseHTTPMaxRedirects checks that the redirect limit is a non-negative whole number.
// It can return the following errors:
// - types.ScriptHTTPOptionError
func parseHTTPMaxRedirects(count float64) (int, error) {
if count < 0 || count != math.Trunc(count) {
return 0, types.NewScriptHTTPOptionError(
httpOptionMaxRedirects,
types.NewScriptTypeError("a whole number of 0 or more", strconv.FormatFloat(count, 'f', -1, 64)),
)
}
return int(count), nil
}
// parseHTTPTimeout parses a Go duration string such as "500ms" or "2s". // parseHTTPTimeout parses a Go duration string such as "500ms" or "2s".
// It can return the following errors: // It can return the following errors:
// - types.ScriptHTTPOptionError // - types.ScriptHTTPOptionError
+23 -5
View File
@@ -100,16 +100,22 @@ func (e *JsEngine) parseHTTPOptions(opts *goja.Object, req *HTTPRequest) error {
if req.Timeout, err = parseHTTPTimeout(timeout); err != nil { if req.Timeout, err = parseHTTPTimeout(timeout); err != nil {
return err return err
} }
case httpOptionInsecure, httpOptionFollowRedirects: case httpOptionInsecure:
flag, ok := value.Export().(bool) flag, ok := value.Export().(bool)
if !ok { if !ok {
return types.NewScriptHTTPOptionError(name, types.NewScriptTypeError("boolean", jsTypeName(value))) return types.NewScriptHTTPOptionError(name, types.NewScriptTypeError("boolean", jsTypeName(value)))
} }
if name == httpOptionInsecure { req.Insecure = flag
req.Insecure = flag case httpOptionMaxRedirects:
} else { count, ok := numberValue(value)
req.FollowRedirects = flag if !ok {
return types.NewScriptHTTPOptionError(name, types.NewScriptTypeError("number", jsTypeName(value)))
}
var err error
if req.MaxRedirects, err = parseHTTPMaxRedirects(count); err != nil {
return err
} }
default: default:
return types.NewScriptHTTPOptionError(name, types.ErrScriptHTTPUnknownOption) return types.NewScriptHTTPOptionError(name, types.ErrScriptHTTPUnknownOption)
@@ -190,3 +196,15 @@ func (e *JsEngine) throw(err error) {
} }
panic(errorValue) panic(errorValue)
} }
// numberValue reports whether value is a JavaScript number, and returns it.
func numberValue(value goja.Value) (float64, bool) {
switch number := value.Export().(type) {
case int64:
return float64(number), true
case float64:
return number, true
default:
return 0, false
}
}
+8 -5
View File
@@ -92,17 +92,20 @@ func (e *LuaEngine) parseHTTPOptions(opts *lua.LTable, req *HTTPRequest) error {
return return
} }
req.Timeout, err = parseHTTPTimeout(string(timeout)) req.Timeout, err = parseHTTPTimeout(string(timeout))
case httpOptionInsecure, httpOptionFollowRedirects: case httpOptionInsecure:
flag, ok := v.(lua.LBool) flag, ok := v.(lua.LBool)
if !ok { if !ok {
err = types.NewScriptHTTPOptionError(name, types.NewScriptTypeError("boolean", v.Type().String())) err = types.NewScriptHTTPOptionError(name, types.NewScriptTypeError("boolean", v.Type().String()))
return return
} }
if name == httpOptionInsecure { req.Insecure = bool(flag)
req.Insecure = bool(flag) case httpOptionMaxRedirects:
} else { count, ok := v.(lua.LNumber)
req.FollowRedirects = bool(flag) if !ok {
err = types.NewScriptHTTPOptionError(name, types.NewScriptTypeError("number", v.Type().String()))
return
} }
req.MaxRedirects, err = parseHTTPMaxRedirects(float64(count))
default: default:
err = types.NewScriptHTTPOptionError(name, types.ErrScriptHTTPUnknownOption) err = types.NewScriptHTTPOptionError(name, types.ErrScriptHTTPUnknownOption)
} }