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

Process all method like POST (with body). #165

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

IgorGalarraga
Copy link

Description of the Change

Originally this example:
curl -v -XGET --data 'test' 'http://localhost:8080/service'
(GET metoth + data on body of request)
does not finalize connection with client.

Quantitative Performance Benefits

With this change, connection closes and responds correctly.
I am not completely sure that it is the best solution.

Verification Process

Using examples/service:
curl -v -XGET --data 'test' 'http://localhost:8080/service'

Applicable Issues

Release Notes

Originally this example:
curl -v -XGET --data 'test' 'http://localhost:8080/service'
does not finalize connection with client.
With this change, connection closes and responds correctly.
@codecov-io
Copy link

codecov-io commented Nov 4, 2019

Codecov Report

Merging #165 into master will decrease coverage by 0.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master    #165      +/-   ##
=========================================
- Coverage   95.31%   95.3%   -0.02%     
=========================================
  Files          35      35              
  Lines        3225    3196      -29     
=========================================
- Hits         3074    3046      -28     
+ Misses        151     150       -1
Impacted Files Coverage Δ
src/httpserver/details/modded_request.hpp 100% <100%> (ø) ⬆️
src/webserver.cpp 90.47% <100%> (-0.03%) ⬇️
test/integ/basic.cpp 99.67% <0%> (-0.02%) ⬇️
src/httpserver/http_request.hpp 95.23% <0%> (+2.38%) ⬆️

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 2a74f9e...73104a4. Read the comment docs.

@etr
Copy link
Owner

etr commented Nov 5, 2019

Thanks for notifying about this bug.

I still feel that GET (and GET-like) methods shouldn't support body provided in input.

See: https://tools.ietf.org/html/rfc7231#section-4.3.1

"A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request."

This commit ( b8f6578 ) going through travis right now should fix the bug you report but enforces the correct semantic of GET.

It should be on head soon. Thanks again!

@etr etr self-assigned this Nov 5, 2019
@etr etr added api Related to libhttpserver's public APIs. bug Confirmed bugs or reports that are very likely to be bugs. labels Nov 5, 2019
@IgorGalarraga
Copy link
Author

I still feel that GET (and GET-like) methods shouldn't support body provided in input.

See: https://tools.ietf.org/html/rfc7231#section-4.3.1

"A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request."

I agree with reject as malformed method..., but, this is the answer of a stardards committe (I will omit which one) about their recommendation to 'post' body content using GET method:

Regarding the use of and application content over a http GET method, 'XXX technical committee' is aware that it is not a common practice, but according to RFCs 7230-7237, the request body is independent of method semantics. It is “allowed” to send a body over HTTP GET method. This convention should be managed by the HTTP server of the unit providing the service.

So, I think the best solution is to support GETs with body AND have the functions to retrieve received data like in POST method:
Piece of code that I used to test into examples/service.cpp into POST and GET methods:

 if (verbose) {
        std::cout << req;
        std::cout << "    Body [ " << req.get_content() << " ]" << std::endl;
    }

If I use POST I can request 'body' but I can't retreive that info if a GET is received.

What do you think? Is there another function to retrieve body content when a GET is received?

Best regards,

@etr
Copy link
Owner

etr commented Nov 6, 2019

I have to say that I disagree. Mostly on two points:

  1. There is a difference in this context between syntax and semantic. Whereas a GET with body might be syntactically correct, it is generally considered bad semantic. It interesting to note how older HTTP-1.1 RFC referred explicitly to how this should not be done (rather than it should be discouraged). I appreciate disagreement on this point, but the overall approach of this library (hopefully not failed too much) has been to push for a clean RESTful semantic.
    In this sense, RESTful offers a very specific tool (POST) which cover those cases where the length of parameters cannot respect the requirements of a GET (with POST having a willingly more ambiguous semantic)

    Providing a block of data, such as the fields entered into an HTML form, to a data-handling process;

Even in this I understand how others have taken different approaches and consider my view - e.g. Elasticsearch allowing for body in GET because they felt that using POST might be inappropriate instead (mostly based on naming of the method).

  1. [minor] Processing the body has a non indifferent cost that would always be payed (e.g. by creating a post-processor) even when, as in the majority of cases, it wouldn't be needed.

For the above, I believe that syntactically the webserver should be immune from erroring when receiving a body (unless specified by the business logic above) but shouldn't support this use-case.

As a general case though, I am quite fond to allow for ideas in disagreement with my recommended view of the world and of how this API should behave. In general, I like to segregate these behaviors using preprocessor directives so that "non-standard" behaviors can be supported to allow for specific needs. I am going to push the current change I have on the separate branch I linked (see: #166). I will be happy to receive a follow-up change from you to support the body-processing use-case if that is kept isolated within preprocessor option. Would that work?

@IgorGalarraga
Copy link
Author

Thank you for your full explanation, I totally agree.

I didn't realize that processing the body has an extra cost, I thought you could look early if the body has any size or not to evaluate processing or not the body, dinamically but without extra complexity.

But after your explanation, I wouldn't make the decision to worsen all requests to support a few exceptions using not recommended semantics.

I think, the preprocessor option (adding a new parameter into 'configure') would be a sufficient and adequate solution. It should also be documented for its easy identification, when the special need arises.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Related to libhttpserver's public APIs. bug Confirmed bugs or reports that are very likely to be bugs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants