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

Fix respect throw option with invalid URLs #2045

Merged
merged 8 commits into from
Jun 8, 2021
Merged

Conversation

imiric
Copy link
Contributor

@imiric imiric commented May 31, 2021

This is a continuation of #1853, with some changes as discussed in that PR.

Closes #1502

Gustavo Chain and others added 2 commits May 31, 2021 16:09
Closes #1502

Notes:
* Not sure if the verification should happen on Request()
* The way throw is disabled on the test feels clunky, it might be a better approach
@imiric imiric requested review from mstoykov and na-- May 31, 2021 14:26
js/modules/k6/http/request.go Outdated Show resolved Hide resolved
lib/netext/httpext/batch.go Outdated Show resolved Hide resolved
@codecov-commenter
Copy link

codecov-commenter commented May 31, 2021

Codecov Report

Merging #2045 (c3a54a7) into master (da5eebc) will increase coverage by 0.07%.
The diff coverage is 89.88%.

❗ Current head c3a54a7 differs from pull request most recent head af755c4. Consider uploading reports for the commit af755c4 to get more accurate results
Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2045      +/-   ##
==========================================
+ Coverage   71.73%   71.81%   +0.07%     
==========================================
  Files         179      179              
  Lines       14100    14124      +24     
==========================================
+ Hits        10115    10143      +28     
- Misses       3347     3349       +2     
+ Partials      638      632       -6     
Flag Coverage Δ
ubuntu 71.74% <89.88%> (+0.07%) ⬆️
windows 71.44% <89.88%> (+0.08%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
lib/netext/httpext/error_codes.go 97.26% <ø> (ø)
lib/netext/httpext/request.go 93.93% <ø> (-0.48%) ⬇️
lib/netext/httpext/url.go 88.00% <88.00%> (ø)
js/modules/k6/http/request.go 83.65% <88.67%> (+3.44%) ⬆️
js/common/util.go 75.00% <100.00%> (+6.25%) ⬆️
js/modules/k6/http/http.go 100.00% <100.00%> (ø)
lib/netext/httpext/response.go 100.00% <100.00%> (ø)
loader/loader.go 79.28% <0.00%> (-3.58%) ⬇️
lib/executor/vu_handle.go 95.23% <0.00%> (+0.95%) ⬆️
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update da5eebc...af755c4. Read the comment docs.

js/modules/k6/http/request.go Outdated Show resolved Hide resolved
imiric pushed a commit that referenced this pull request Jun 4, 2021
I decided to add some duplication after all and check for Throw in both
HTTP.Request and HTTP.Batch, for a couple of reasons:

- Checking of options and especially logging should be done in functions
  "closer" to the user, and shouldn't concern internal functions.
- Moving this check outside simplifies the internal functions,
  particularly batch request ones, since they don't have to handle the
  case of an empty ParsedHTTPRequest.

Resolves #2045 (comment)
imiric pushed a commit that referenced this pull request Jun 4, 2021
imiric pushed a commit that referenced this pull request Jun 4, 2021
I decided to add some duplication after all and check for Throw in both
HTTP.Request and HTTP.Batch, for a couple of reasons:

- Checking of options and especially logging should be done in functions
  "closer" to the user, and shouldn't concern internal functions.
- Moving this check outside simplifies the internal functions,
  particularly batch request ones, since they don't have to handle the
  case of an empty ParsedHTTPRequest.

Resolves #2045 (comment)
imiric pushed a commit that referenced this pull request Jun 4, 2021
@imiric imiric force-pushed the fix/1502-throw-invalid-url branch from 0970583 to 283d4bd Compare June 4, 2021 16:30
@imiric
Copy link
Contributor Author

imiric commented Jun 4, 2021

@na-- @mstoykov This is ready for review now.

I did things a bit differently than discussed in #1853. See my rationale in 17f6df6.

Ivan Mirić added 2 commits June 4, 2021 18:47
I decided to add some duplication after all and check for Throw in both
HTTP.Request and HTTP.Batch, for a couple of reasons:

- Checking of options and especially logging should be done in functions
  "closer" to the user, and shouldn't concern internal functions.
- Moving this check outside simplifies the internal functions,
  particularly batch request ones, since they don't have to handle the
  case of an empty ParsedHTTPRequest.

Resolves #2045 (comment)
@imiric imiric force-pushed the fix/1502-throw-invalid-url branch from 283d4bd to b894ab7 Compare June 4, 2021 16:47
) (*httpext.ParsedHTTPRequest, error) {
rt := common.GetRuntime(ctx)
state := lib.GetState(ctx)
if state == nil {
return nil, ErrHTTPForbiddenInInitContext
}

u, err := httpext.ToURL(reqURL.Export())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I think goja.Runtime.ToValue() is a relatively expensive operation. We'd probably be better off if reqURL was of an interface{} type here, and we had a check like this here:

Suggested change
u, err := httpext.ToURL(reqURL.Export())
if urlJSValue, ok := reqURL.(goja.Value); ok {
reqURL = urlJSValue.Export()
}
u, err := httpext.ToURL(reqURL)

This way we won't have to covert the url from a JS value to a Go one, and back to a JS value, and back to a go value.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably true .... but given this common.Bind code (among other):
https://github.com/k6io/k6/blob/da5eebc638d9917cedfe98e232a7eed4cb69a157/js/common/bridge.go#L231-L236
I am not certain ... how much of a saving this will be 🤷

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved by 39a0ed9.

if err != nil {
return nil, err
}
case string, httpext.URL:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you keep the comment from the previous default clause ?

Copy link
Contributor Author

@imiric imiric Jun 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hhmm but the comment doesn't make sense anymore since it was for the ToURL() call, which is now done in parseRequest().

Though would it be better to leave this as default and just pass anything to rt.ToValue()?

EDIT: I changed it to default in 39a0ed9.

return nil, err
}
state.Logger.WithField("error", err).Warn("A batch request failed")
return rt.ToValue(results), nil
Copy link
Contributor

@mstoykov mstoykov Jun 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading ToValue documentation has the following paragraph(near the very end, a few pages down):

Any other Go function is wrapped so that the arguments are automatically converted into the required Go types and the return value is converted to a JavaScript value (using this method). If conversion is not possible, a TypeError is thrown.

Which to me means that most of our usage of rt.ToValue is probably not necessary, including this one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually looking at common.Bind where we actually return func(call goja.FunctionCall) goja.Value and have to ToValue we apparently call it regardless ... so again even less needed. But Goja would've called it, either way, it's just that in this case we wrap this particular function call ... instead of goja doing it 🤦
https://github.com/k6io/k6/blob/da5eebc638d9917cedfe98e232a7eed4cb69a157/js/common/bridge.go#L246-L253

Also the part about multiple return values will not work ... and you can very easily make k6 panic if you write the wrong go code like func SomeThingThatGetsBinded() (string, string) ....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for confirming this. I've seen both usages used, but it's good to know we don't have to convert it beforehand.

Resolved by 6b8cd30.

imiric pushed a commit that referenced this pull request Jun 7, 2021
To minimize the amount of Go->JS->Go conversions.

Resolves #2045 (comment)
imiric pushed a commit that referenced this pull request Jun 7, 2021
Ivan Mirić added 2 commits June 7, 2021 13:11
@imiric imiric force-pushed the fix/1502-throw-invalid-url branch from 5fa6898 to 6b8cd30 Compare June 7, 2021 11:11
return nil, err
}
state.Logger.WithField("error", err).Warn("Request Failed")
return &Response{Response: &httpext.Response{}}, nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am for this to be created from some function and to include more stuff as currently response.json() ends up as a panic instead of simple(r) exception, this will likely be true for everything.
Also I would argue that this should still have error and error_code set accordingly to what the problem was so you can detect what actually got wrong in the code.

Copy link
Contributor Author

@imiric imiric Jun 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-/ I still think it's strange to work with a Response object if a request was never made. IMO the correct behavior in this case would be to simply throw the parse exception and let the user handle it with try/catch as usual, in which case they'd have access to the error object. But since the Throw option is so old and we don't promote try/catch at all (it's nowhere in our docs 😞) we've backed ourselves into this corner where we have to return a fake-valid Response object. Would it be too late to bring up the discussion of deprecating Throw?

I'll see how I can improve things so that at least there are no panics, but this feels way off.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah... 😞 This is definitely one of the things that we have to improve in the new HTTP API... Not sure exactly how we should improve it, considering the context and requirements of load testing, but it has so many corner cases and footguns... 😞

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, this is a requirement for the merging of this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mstoykov Please take a look at the latest 2 commits.

na--
na-- previously approved these changes Jun 8, 2021
Copy link
Member

@na-- na-- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, or at least didn't spot any issues in the code, but I haven't actually tested it for other things like https://github.com/k6io/k6/pull/2045#discussion_r646554675

This is crappy in several ways... One of which is that calling json() on
the empty Response will fail parsing the body as JSON, and this failure
does *not* respect the Throw option either and the iteration will be
interrupted. But at least it doesn't panic...

Resolves #2045 (comment)
if state.Options.Throw.Bool {
return nil, err
}
state.Logger.WithField("error", err).Warn("A batch request failed")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we fine with this returning a different message than for a single request failure (Request Failed)? I thought it would be useful for troubleshooting to know it was a batch request, but maybe this should have the same message for consistency?

na--
na-- previously approved these changes Jun 8, 2021
@imiric imiric force-pushed the fix/1502-throw-invalid-url branch from c87d6d1 to af755c4 Compare June 8, 2021 12:44
@imiric
Copy link
Contributor Author

imiric commented Jun 8, 2021

Sorry for dismissing your review @na--, I kept finding some minor test tweaks ;) Hopefully should be good now.

Copy link
Member

@na-- na-- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, though again, I haven't tested this yet, I'll do it after we merge in master, together with everything else for the next release

@imiric imiric merged commit b9a29eb into master Jun 8, 2021
@imiric imiric deleted the fix/1502-throw-invalid-url branch June 8, 2021 15:01
@na-- na-- added this to the v0.33.0 milestone Jun 8, 2021
imiric pushed a commit to grafana/k6-docs that referenced this pull request Jun 29, 2021
imiric pushed a commit to grafana/k6-docs that referenced this pull request Jun 29, 2021
imiric pushed a commit to grafana/k6-docs that referenced this pull request Jun 29, 2021
harrytwigg pushed a commit to APITeamLimited/globe-test that referenced this pull request Jan 11, 2023
I decided to add some duplication after all and check for Throw in both
HTTP.Request and HTTP.Batch, for a couple of reasons:

- Checking of options and especially logging should be done in functions
  "closer" to the user, and shouldn't concern internal functions.
- Moving this check outside simplifies the internal functions,
  particularly batch request ones, since they don't have to handle the
  case of an empty ParsedHTTPRequest.

Resolves grafana/k6#2045 (comment)
harrytwigg pushed a commit to APITeamLimited/globe-test that referenced this pull request Jan 11, 2023
harrytwigg pushed a commit to APITeamLimited/globe-test that referenced this pull request Jan 11, 2023
To minimize the amount of Go->JS->Go conversions.

Resolves grafana/k6#2045 (comment)
harrytwigg pushed a commit to APITeamLimited/globe-test that referenced this pull request Jan 11, 2023
harrytwigg pushed a commit to APITeamLimited/globe-test that referenced this pull request Jan 11, 2023
This is crappy in several ways... One of which is that calling json() on
the empty Response will fail parsing the body as JSON, and this failure
does *not* respect the Throw option either and the iteration will be
interrupted. But at least it doesn't panic...

Resolves grafana/k6#2045 (comment)
harrytwigg pushed a commit to APITeamLimited/globe-test that referenced this pull request Jan 11, 2023
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

Successfully merging this pull request may close these issues.

throw option not respected with malformed URLs
4 participants