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

add allow_head to add_get #1668

Merged
merged 3 commits into from
Feb 22, 2017
Merged

add allow_head to add_get #1668

merged 3 commits into from
Feb 22, 2017

Conversation

samuelcolvin
Copy link
Member

@samuelcolvin samuelcolvin commented Feb 21, 2017

What do these changes do?

Add the allow_head keyword argument for add_get to encourage aiohttp server applications to correctly implement http and allow HEAD requests to endpoints generally used for GET requests.

Also adds app.router.set_defaults(allow_head=True) to switch behaviour of all endpoints for the app.

Related issue number

#1618

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes
  • Add yourself to CONTRIBUTORS.txt
    • The format is <Name> <Surname>.
    • Please keep alphabetical order, the file is sorted by names.
  • Add a new entry to CHANGES.rst
    • Choose any open position to avoid merge conflicts with other PRs.
    • Add a link to the issue you are fixing (if any) using #issue_number format at the end of changelog message. Use Pull Request number if there are no issues for PR or PR covers the issue only partially.

@codecov-io
Copy link

codecov-io commented Feb 21, 2017

Codecov Report

Merging #1668 into master will decrease coverage by -1.63%.
The diff coverage is 100%.

@@            Coverage Diff             @@
##           master    #1668      +/-   ##
==========================================
- Coverage   96.77%   95.15%   -1.63%     
==========================================
  Files          37       37              
  Lines        7360     7365       +5     
  Branches     1268     1269       +1     
==========================================
- Hits         7123     7008     -115     
- Misses        127      222      +95     
- Partials      110      135      +25
Impacted Files Coverage Δ
aiohttp/abc.py 98.18% <ø> (-1.82%)
aiohttp/web_urldispatcher.py 98.83% <100%> (-0.58%)
aiohttp/client.py 90.81% <ø> (-7.22%)
aiohttp/streams.py 93% <ø> (-5.6%)
aiohttp/test_utils.py 95.25% <ø> (-4.38%)
aiohttp/client_ws.py 94.02% <ø> (-4.35%)
aiohttp/multipart.py 91.82% <ø> (-3.54%)
aiohttp/worker.py 96.63% <ø> (-3.37%)
aiohttp/web_ws.py 91.96% <ø> (-3.22%)
... and 6 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 82d7566...0eb1888. Read the comment docs.

@@ -755,6 +756,9 @@ def routes(self):
def named_resources(self):
return MappingProxyType(self._named_resources)

def set_defaults(self, *, allow_head):
Copy link
Member

Choose a reason for hiding this comment

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

I doubt if we need default for the flag.
It might lead to many confusing cases, e.g. if third party library has something like register_routes(router, prefix) method its behavior varies depending on outer flag.

Copy link
Member Author

@samuelcolvin samuelcolvin Feb 21, 2017

Choose a reason for hiding this comment

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

Humm, ok I'll remove it if you prefer. But the current setup is wrong according to the RFC and without the option to set the default you have to explicitly set allow_head=True on every route you add:

RFC 7231:

The server SHOULD send the same
header fields in response to a HEAD request as it would have sent if
the request had been a GET, except that the payload header fields
(Section 3.3) MAY be omitted.

For me, the simplest, clearest and most correct option would be to have allow_head=True by default.

Copy link
Member

Choose a reason for hiding this comment

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

problem is, we currently do not control when handler writes body, so in most cases
developer needs to support head explicitly

Copy link
Member Author

@samuelcolvin samuelcolvin Feb 22, 2017

Choose a reason for hiding this comment

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

The developer can choose to support head explicitly but nothing breaks if they don't.

Allowing HEAD to endpoints which act like they got a GET request and still write body doesn't break anything.

Both django and flask allow users to still (by default) write body even for HEAD requests. I'm not saying they're always right, but their solution is more correct than aiohttp currently.

Here's an example:

app.py:

import asyncio
from aiohttp import web

async def handle(request):
    print('preparing slow response...')
    await asyncio.sleep(2, loop=request.app.loop)
    return web.Response(body=b'this is the body\n')

app = web.Application()
app.router.add_get('/', handle, allow_head=True)

web.run_app(app, host='localhost', port=8000)

shell:

~ ➤  curl -v http://localhost:8000
* Rebuilt URL to: http://localhost:8000/
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Length: 17
< Content-Type: application/octet-stream
< Date: Wed, 22 Feb 2017 10:08:03 GMT
< Server: Python/3.5 aiohttp/2.0.0a0
< 
this is the body
* Connection #0 to host localhost left intact
~ ➤  curl -I http://localhost:8000
HTTP/1.1 200 OK
Content-Length: 17
Content-Type: application/octet-stream
Date: Wed, 22 Feb 2017 10:08:10 GMT
Server: Python/3.5 aiohttp/2.0.0a0

~ ➤  

Nothing went wrong here.

The app could choose to notice the HEAD request and not spend a lot of time/resources writing body, but I don't see any problem if those not concerned by this (fairly niche) optimisation don't bother with it.

In summary: your current approach explicitly contravenes the HTTP RFC. The issue you're worried about is an optimisation which will apply in a very small percentage of requests and where app authors already have all the tools they need to achieve the optimization.

Copy link
Member

Choose a reason for hiding this comment

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

Ok. Let's remove url dispatch part and change default allow_head to True

Copy link
Member Author

Choose a reason for hiding this comment

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

Great. I've updated the PR.

@samuelcolvin
Copy link
Member Author

samuelcolvin commented Feb 21, 2017

This is failing due to an error in docs I've fixed in #1669 fixed

@fafhrd91
Copy link
Member

very good

@lock
Copy link

lock bot commented Oct 29, 2019

This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.

If you feel like there's important points made in this discussion,
please include those exceprts into that new issue.

@lock lock bot added the outdated label Oct 29, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Oct 29, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants