Skip to content

Upgrade Apache HttpClient 4.5.13 -> 5.1.3 #35

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

Merged
merged 10 commits into from
Sep 14, 2022
Merged

Conversation

labkey-adam
Copy link
Contributor

@labkey-adam labkey-adam commented Sep 7, 2022

Rationale

Latest

Related Pull Requests

  • Upgrade Apache HttpClient 4.5.13 -> 5.1.3
  • Switch to Basic auth challenge/response, instead of pre-emptive auth
  • Switch self-signed cert handling to HttpClient 5.x approach: SSLConnectionSocketFactory must now be set on the ConnectionManager, not on each HttpClientBuilder.
  • Switch to adding parameters one-by-one to ensure correct escaping (see Command.addParameters()). setCustomQuery() now requires an unescaped query string, which is not compatible with tricky characters (e.g., "&" in a schema name).
  • Remove deprecated methods

…()` now requires an unescaped query string, which is not compatible with tricky characters (e.g., "&" in a schema name).
api ("com.googlecode.json-simple:json-simple:${jsonSimpleVersion}")
{
// exclude this because it gets in the way of our own JSON object implementations from server/api
exclude group: "org.json", module:"json"
}
api "org.apache.httpcomponents.client5:httpclient5:${httpclient5Version}"
api "org.apache.httpcomponents.core5:httpcore5:${httpcore5Version}"
Copy link
Contributor

Choose a reason for hiding this comment

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

Just checking that these are actually api dependencies (that is, we expose some objects from these jar files in our interfaces). I assume so since they were before.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, unfortunately our wrappers expose a few native HttpClient/HttpCore classes. For example, our Connection.executeRequest() returns CloseableHttpResponse (from HttpClient) which implements ClassicHttpResponse (from HttpCore). I've made a few internal methods private in this PR to reduce the leakage, but we can't eliminate it without more work.

Copy link
Member

@labkey-tchad labkey-tchad left a comment

Choose a reason for hiding this comment

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

Connection.stopImpersonating seems to be broken.
Biologics tests use it fairly broadly and it seems to be failing every time:

org.labkey.remoteapi.CommandException: Failed to stop impersonating
  at app//org.labkey.remoteapi.Connection.stopImpersonate(Connection.java:403)
  at app//org.labkey.test.util.TestUser.stopImpersonating(TestUser.java:123)
  at app//org.labkey.test.tests.biologics.crossfolder.CrossFolderRegistryTest.testSubfolderUserCanEditSubfolderSequence(CrossFolderRegistryTest.java:584)

@labkey-adam
Copy link
Contributor Author

Connection.stopImpersonating seems to be broken. Biologics tests use it fairly broadly and it seems to be failing every time:

org.labkey.remoteapi.CommandException: Failed to stop impersonating
  at app//org.labkey.remoteapi.Connection.stopImpersonate(Connection.java:403)
  at app//org.labkey.test.util.TestUser.stopImpersonating(TestUser.java:123)
  at app//org.labkey.test.tests.biologics.crossfolder.CrossFolderRegistryTest.testSubfolderUserCanEditSubfolderSequence(CrossFolderRegistryTest.java:584)

Yep, I noticed that. Not sure if it's returning a different status code now or what.

@labkey-tchad
Copy link
Member

Yep, I noticed that. Not sure if it's returning a different status code now or what.

I just ran it locally. It is getting a 200 response now. The normal "Stop Impersonating" button (which hits the same action), still returns a 302.

@labkey-adam
Copy link
Contributor Author

Yep, I noticed that. Not sure if it's returning a different status code now or what.

I just ran it locally. It is getting a 200 response now. The normal "Stop Impersonating" button (which hits the same action), still returns a 302.

Yes, I believe the button causes JavaScript to do a window.location.replace() to redirect. The server is now responding to the API call with that same HTML and 200. I haven't figured out why yet.

@labkey-tchad
Copy link
Member

Yes, I believe the button causes JavaScript to do a window.location.replace() to redirect. The server is now responding to the API call with that same HTML and 200. I haven't figured out why yet.

Whatever is happening, it seems to be localized to the remote API. StopImpersonatingCommand gets a 200 response even when targeting a 22.7 server; it even gets the same HTML view with window.location.replace. I wonder if the new httpclient is following redirects automatically.

@labkey-adam
Copy link
Contributor Author

Yes, I believe the button causes JavaScript to do a window.location.replace() to redirect. The server is now responding to the API call with that same HTML and 200. I haven't figured out why yet.

Whatever is happening, it seems to be localized to the remote API. StopImpersonatingCommand gets a 200 response even when targeting a 22.7 server; it even gets the same HTML view with window.location.replace. I wonder if the new httpclient is following redirects automatically.

Just stepped through the client code and yes, that's exactly what's happening. Need to ask the HttpClient not to follow redirects or else accept 200 as success.

Copy link
Member

@labkey-tchad labkey-tchad left a comment

Choose a reason for hiding this comment

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

While we're breaking backward compatibility, could we rename Connection.stopImpersonate to stopImpersonating?

Comment on lines +553 to 556
catch (URISyntaxException e)
{
throw new CommandException(e.getMessage());
}
Copy link
Member

Choose a reason for hiding this comment

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

setParameters is declared as throwing URISyntaxException, why not just let this bubble up instead of wrapping in a CommandException?
Also, I would argue that Command._execute shouldn't wrap it in a CommandException either. Wrapping in an IllegalArgumentException seems more appropriate to me since the most likely cause of such an exception is somebody specifying bad query parameters or some such thing.
Although, I suppose, throwing unchecked exceptions from an API is probably bad practice.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was just following the existing pattern, which I agree is inconsistent. As I think I noted somewhere, I'm planning to merge the create URL and add parameters steps into a single method at some point. Will look at reconciling exception handling at that point. But I think this set of PRs is close enough and I need to move on...

@labkey-adam
Copy link
Contributor Author

@labkey-tchad as you may have seen, I just added a new StopImpersonatingApiAction that doesn't redirect and shifted the remote API to use it. And I restored the default redirect behavior. We'll see what all the tests think of that...

@@ -10,6 +10,6 @@ public class StopImpersonatingCommand extends PostCommand<CommandResponse>
{
public StopImpersonatingCommand()
{
super("login", "stopImpersonating.api");
super("login", "stopImpersonatingApi.api");
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure what advantage this has. It seems to just break backward compatibility.

@labkey-adam
Copy link
Contributor Author

Sorry for the delay... was distracted with moving yesterday. Thought is it's cleaner to have our libraries call API actions (more appropriate error and success handling, API-appropriate return values) and I wanted to avoid the pointless redirect. But I hear you on backward compatibility. New plan: I think I've figured out how to disable redirects for this specific Command and will revert to calling the non-API action. But I'll leave the API action in place (and fix the error case) so we can switch to it in the future, e.g., when it's been in the server for a couple years.

@labkey-adam
Copy link
Contributor Author

...which of course means we're back to a 302 response from that Command :)

@labkey-adam
Copy link
Contributor Author

While we're breaking backward compatibility, could we rename Connection.stopImpersonate to stopImpersonating?

I added stopImpersonating() and deprecated stopImpersonate(). We'll leave the old method in place for a while.

…ards compatibility. Disable redirects just for this command.

Connection.stopImpersonating()
Copy link
Contributor

@labkey-jeckels labkey-jeckels left a comment

Choose a reason for hiding this comment

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

Looks OK to me

@labkey-adam labkey-adam merged commit 6ba3150 into develop Sep 14, 2022
@labkey-adam labkey-adam deleted the fb_httpclient branch September 14, 2022 20:59
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.

4 participants