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

instrumentation of http{s}.request() has a few edge case issues #2044

Closed
trentm opened this issue Apr 13, 2021 · 2 comments · Fixed by #3090
Closed

instrumentation of http{s}.request() has a few edge case issues #2044

trentm opened this issue Apr 13, 2021 · 2 comments · Fixed by #3090
Assignees
Labels
8.7-candidate agent-nodejs Make available for APM Agents project planning.

Comments

@trentm
Copy link
Member

trentm commented Apr 13, 2021

In lib/instrumentation/http-shared.js the traceOutgoingRequest function that handles instrumenting http.request and https.request has a few issues:

      var options = {}
      var newArgs = [options]
      for (const arg of args) {
        if (typeof arg === 'function') {
          newArgs.push(arg)
        } else {
          Object.assign(options, ensureUrl(arg))
        }
      }
  1. That iteration through all args changes the signature of http.request() such that you can pass any number of objects and URLs to it -- before and after a callback function. Not a biggie.
  2. That ensureUrl uses a formatURL function that is meant to be (or should be) an equivalent to node core's handling (https://github.com/nodejs/node/blob/8d9d8236b79ea91640f973cc8c1423603694b482/lib/internal/url.js#L1288-L1311) but misses a few things:

I wonder if it would be possible to avoid full processing of the original args, only try to sniff out and update an "options.headers" object. Then the agent doesn't have to try to track change made to node's internal "urlToHttpOptions" handling.

One side-effect of ^^ is that the potential handling for extracting the "url", see #2039, may have to change to handle inspecting those original args itself. I believe that would be preferable to changing the behaviour of http.request.

@github-actions github-actions bot added the agent-nodejs Make available for APM Agents project planning. label Apr 13, 2021
@astorm astorm self-assigned this Apr 14, 2021
@astorm
Copy link
Contributor

astorm commented Apr 14, 2021

I wonder if it would be possible to avoid full processing of the original args, only try to sniff out and update an "options.headers" object. Then the agent doesn't have to try to track change made to node's internal "urlToHttpOptions" handling.

My thinking is similar.

Looking at the code here, it appears that that only property of the extracted options variable that our function uses is options.headers. It is not, to my knowledge, possible to extract a headers value from a URL string or object. In other words, it's not necessary to merge the URL data to get the value we want (options.headers). Sniffing out the options object, and then passing the original arguments (with a modified options object) seems like the best course of action, with one caveat.

Here's all the method signatures of http.request

  // Three Argument:
  // http.request(string|String|URL url, object options, function callback)
  //
  // Two Argument:
  // http.request(string|String|URL url, object options)
  // http.request(string|String|URL url, function callback)
  // http.request(object options, function callback)
  //
  // One Argument:
  // http.request(string|String|URL url)
  // http.request(object options)
  // http.request(function callback)

  // No Arguments:
  // http.request()

There's two that don't have an options object.

// http.request(string|String|URL url)
// http.request(string|String|URL url, function callback)

For these method signatures we'll need to generate an empty options object and then either push or splice it onto the original args.

@astorm astorm removed their assignment Apr 14, 2021
trentm added a commit that referenced this issue Jan 14, 2023
This change updates the argument munging that is done for the wrapping
of `http.request` et al to fix some cases where the instrumentation
would *change the behaviour* of the function.  The main fix here is
that before this change the conversion of a URL instance to request
options would accidentally drop basic auth info (the 'username' and
'password' fields).

This issue has existed since v2.17.0. It was introduced in commit dd60b12
when switching directly from `url.parse()` to `new URL()`. Recent
versions of node have a `url.urlToHttpOptions()` to help with this
conversion.

Fixes: #2044
Refs: https://discuss.elastic.co/t/issue-apm-agent-with-backend-requests-username-password-url/322903
@trentm
Copy link
Member Author

trentm commented Jan 14, 2023

This issue has existed since v2.17.0. It was introduced in commit dd60b12 when switching directly from url.parse() to new URL(). Recent versions of node have a url.urlToHttpOptions() to help with this conversion.

@trentm trentm self-assigned this Jan 14, 2023
trentm added a commit that referenced this issue Jan 17, 2023
)

This change updates the argument munging that is done for the wrapping
of `http.request` et al to fix some cases where the instrumentation
would *change the behaviour* of the function.  The main fix here is
that before this change the conversion of a URL instance to request
options would accidentally drop basic auth info (the 'username' and
'password' fields).

This issue has existed since v2.17.0. It was introduced in commit dd60b12
when switching directly from `url.parse()` to `new URL()`. Recent
versions of node have a `url.urlToHttpOptions()` to help with this
conversion.

Fixes: #2044
Fixes: #2382
Refs: https://discuss.elastic.co/t/issue-apm-agent-with-backend-requests-username-password-url/322903
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
8.7-candidate agent-nodejs Make available for APM Agents project planning.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants