Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to stop following 30x redirects #407

Open
mikyk10 opened this issue Apr 4, 2024 · 2 comments
Open

Unable to stop following 30x redirects #407

mikyk10 opened this issue Apr 4, 2024 · 2 comments

Comments

@mikyk10
Copy link

mikyk10 commented Apr 4, 2024

Thank you for taking your time to maintain this grateful tool! This tool has tremendously improved our product.
One thing I found in this tool could make somewhat difficult to write an E2E test case. Here's description.

If you can give feedback here, I am happy to submit PR as well.

Description

I am developing a proxy-server product that is designed to return 30x redirects based on its backend server configurations/response. Currently, the http.Client used within the tool automatically follows 30x redirects, as CheckRedirect is not configured to handle or restrict this behavior. As a result, test cases that expect 30x redirects fail.

Any guidance on how to modify the test case to stop automatically following 30x redirects, and instead return the raw 30x response directly to the test case, would be appreciated.

Example Scenario Case

  - title: 302 Found Case
    protocol: https
    request:
      method: GET
      url: 'https://httpbin.org/redirect-to?url=https%3A%2F%2Fwww.example.com%2F&status_code=302'
    expect:
      code: Found

Proposed Solution

  • Add an option to choose whether or not to follow redirects.
  • Add CheckRedirect callback to read the option and returns special error if needed.
func (r *Request) buildClient(ctx *context.Context) (*http.Client, error) {
	client := &http.Client{
		Transport: &charsetRoundTripper{
			base: &encodingRoundTripper{
				base: http.DefaultTransport,
			},
		},
	}

	// The following change could break existing test cases that implicitly expect `http.Client` to follow 30x redirects.
	// There should be some conditional code according to its test scenario.
	client.CheckRedirect = func(x *http.Request, via []*http.Request) error {
		return http.ErrUseLastResponse
	}

Sidenote

It seems the buildClient(ctx *context.Context) reads steps[].request.client in yaml and do a type assesion to get *http.Client. Is there any way to embed *http.Client with CheckRedirect configured in the yaml??? I still do not get what the .client is.

@zoncoen
Copy link
Owner

zoncoen commented Apr 13, 2024

Thank you for your polite feedback! I agree with your suggestion.
If you send a PR, please add an option like the following.

type Request struct {
	Client  string          `yaml:"client,omitempty"`
	Method  string          `yaml:"method,omitempty"`
	URL     string          `yaml:"url,omitempty"`
	Query   interface{}     `yaml:"query,omitempty"`
	Header  interface{}     `yaml:"header,omitempty"`
	Body    interface{}     `yaml:"body,omitempty"`
	Options *RequestOptions `yaml:"options,omitempty"`
}

type RequestOptions struct {
	Redirect *RedirectPolicy `yaml:"redirect,omitempty"`
}

type RedirectPolicy struct {
	MaxRedirects   *int `yaml:"maxRedirects,omitempty"`
	UseLastReponse bool `yaml:"useLastResponse,omitempty"`
}

func (p *RedirectPolicy) build() func(*http.Request, []*http.Request) error {
	if p == nil {
		return nil // use the Go's default
	}
	return func(req *http.Request, via []*http.Request) error {
		// ...
	}
}

@zoncoen
Copy link
Owner

zoncoen commented Apr 14, 2024

I still do not get what the .client is.

It is a field for passing a custom HTTP client by using the plugin feature. It can also be used to stop redirection.

title: check redirection
plugins:
  client: client.so
steps:
- title: check redirection
  protocol: http
  request:
    client: '{{plugins.client.NoRedirection}}'
    method: GET
    url: http://example.com/a
  expect:
    code: Found
    header:
      Location: http://example.com/b
package main

import (
	"net/http"

	"github.com/zoncoen/scenarigo/plugin"
)

func init() {
	plugin.RegisterSetup(setup)
}

var NoRedirection *http.Client

func setup(ctx *plugin.Context) (*plugin.Context, func(*plugin.Context)) {
	NoRedirection = &http.Client{
		CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
			return http.ErrUseLastResponse
		},
	}
	return ctx, nil
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants