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

HttpController's ADD_METHOD_TO breaks in some cases #2130

Open
Mis1eader-dev opened this issue Aug 18, 2024 · 10 comments
Open

HttpController's ADD_METHOD_TO breaks in some cases #2130

Mis1eader-dev opened this issue Aug 18, 2024 · 10 comments
Labels
bug Something isn't working

Comments

@Mis1eader-dev
Copy link
Member

Describe the bug
I have a few HttpControllers and HttpSimpleControllers mixed together, and noticed today that only one of the HttpControllers was returning status 400, which is a status code I use for incorrect input in the URL.
I went exactly to the controller in question and added a print statement to check if it was the one getting called, and it turns out it isn't.
I then prefixed its URI with something that differs from all the other controllers and then I hit the new URI, and it returned a status 200.
I went to another controller which has about the same structure but has a constant in its URI, and put a print statement and saw it had been hitting that incorrect API endpoint.

To Reproduce
Couldn't reproduce it within a small project, here's how the two API endpoints in question roughly look like:

class Get : public HttpController<Get>
{
public:
	void asyncHandleHttpRequest(
		const HttpRequestPtr& req,
		std::function<void (const HttpResponsePtr&)>&& callback,
		string&& city,
		string&& id
	);

	METHOD_LIST_BEGIN
		ADD_METHOD_TO(
			Get::asyncHandleHttpRequest,
			"/api/clients/{client-city}/{client-id}",
			HttpMethod::Get,
		);
	METHOD_LIST_END
};

class Get2 : public HttpController<Get2>
{
public:
	void asyncHandleHttpRequest(
		const HttpRequestPtr& req,
		std::function<void (const HttpResponsePtr&)>&& callback,
		string&& id
	);

	METHOD_LIST_BEGIN
		ADD_METHOD_TO(
			Get2::asyncHandleHttpRequest,
			"/api/clients/users/{user-id}",
			HttpMethod::Get,
		);
	METHOD_LIST_END
};

Here the API endpoint that overshadowed the other was Get.

Will see if I can make a reproduceable example instead once I have time.

Expected behavior
Should have hit the API endpoint that looks closest to the actual URL.

@Mis1eader-dev
Copy link
Member Author

Turns out it's because there were two HttpSimpleController APIs, one with no query params, one with query params, and the one was getting hit that required a query params.

@Mis1eader-dev
Copy link
Member Author

Actually I thought it was another API causing this, but the API in question is still not working unless I change the prefix of the API endpoint, here is the API that is not working:

METHOD_LIST_BEGIN
	ADD_METHOD_TO(
		GetSelf::asyncHandleHttpRequest,
		"/api/clients/device-groups/{device-group-id}",
		API_LOGGED_IN_FILTERS,
		HttpMethod::Get,
	);
METHOD_LIST_END

And here is the API that overshadows the above API:

METHOD_LIST_BEGIN
	ADD_METHOD_TO(
		Get::asyncHandleHttpRequest,
		"/api/clients/{user-group-city}/{user-group-id}",
		API_LOGGED_IN_FILTERS,
		HttpMethod::Get,
	);
METHOD_LIST_END

@Mis1eader-dev Mis1eader-dev reopened this Aug 22, 2024
@Mis1eader-dev
Copy link
Member Author

I believe Drogon is picking the 2nd one greedily, not knowing there is another API that matches the prefix closer to the actual req->path()

@Mis1eader-dev
Copy link
Member Author

The plugin I wrote in this PR is not greedy and picks the one that matches the closest to the actual path, we can improve upon it and use it as both a matcher and redirector built into Drogon

@an-tao what is your opinion on this? Or do we just make the current algorithm not greedy?

@Mis1eader-dev
Copy link
Member Author

Mis1eader-dev commented Aug 22, 2024

New findings, if I change the not working API to this:

"/api/clientss/device-groups/{device-group-id}"

Note the double 's' in clients, it works.

However if I do this:

"/api/clients/device-groupss/{device-group-id}"

Note the double 's' in device-groups, then it doesn't work.

There is something strange happening with the current algorithm.

I also tried increasing and decreasing the length of the string to see if the algorithm breaks these two APIs apart, but it didn't work for either case:

"/api/clients/device-groups/{device-group-id-longer}"
"/api/clients/device-groups/{device}"

@an-tao
Copy link
Member

an-tao commented Aug 22, 2024

The plugin I wrote in this PR is not greedy and picks the one that matches the closest to the actual path, we can improve upon it and use it as both a matcher and redirector built into Drogon

@an-tao what is your opinion on this? Or do we just make the current algorithm not greedy?

I just feel that the logic of this redirector solution is too complex for users—it's even confusing me. And some other developers have expressed similar views, so I put it on hold.

@Mis1eader-dev
Copy link
Member Author

@an-tao the PR aside, what is the plan for this bug in method matchers? Do I need to provide an example branch that replicates the bug?

@an-tao
Copy link
Member

an-tao commented Aug 22, 2024

@an-tao the PR aside, what is the plan for this bug in method matchers? Do I need to provide an example branch that replicates the bug?

Yes, please, thanks.

@Mis1eader-dev
Copy link
Member Author

@an-tao this is a reproduceable example of the bug.

The G controller overshadows the D controller.

@Mis1eader-dev
Copy link
Member Author

Turns out all the other controllers aren't necessary to trigger this bug. See this commit which produces the same bug.

Strangely enough, swapping the order of their declarations will make the bug go away.

@Mis1eader-dev Mis1eader-dev added the bug Something isn't working label Sep 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants