Opened 13 years ago
Closed 12 years ago
#17474 closed Bug (wontfix)
Problem when the request doesn't have Content-Type.
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | HTTP handling | Version: | 1.4 |
Severity: | Normal | Keywords: | content-type |
Cc: | olau@…, Ivan Virabyan, purohit@… | Triage Stage: | Design decision needed |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
I don't know exactly why, but some ajax requests don't have Content-Type header.
When this happens, when I try to get request.POST
, I got the following exception: 'NoneType' object has no attribute 'startswith'
,
raised by method _load_post_and_files
at line 270 of django/http/__init__.py
.
The problem is that when the request doesn't have Content-Type, self.META.get('CONTENT_TYPE', '')
returns None
.
To fix the problem I just did it:
content_type = self.META.get('CONTENT_TYPE', None) or '' if content_type.startswith('multipart'):
Change History (14)
comment:1 by , 13 years ago
Description: | modified (diff) |
---|
comment:2 by , 13 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
The error you're reporting means that self.META['CONTENT_TYPE'] == None
— if it were undefined, self.META.get('CONTENT_TYPE', '')
would return ''
, not None
.
request.META['CONTENT_TYPE']
is defined in WSGIRequestHandler.get_environ
like this:
if self.headers.typeheader is None: env['CONTENT_TYPE'] = self.headers.type else: env['CONTENT_TYPE'] = self.headers.typeheader
This code is copy-pasted from wsgiref.simple_server (line 90), and self.headers
comes from BaseHTTPRequestHandler.headers.
self.headers.type
is computed in Message.parse_type, which sets self.type = '/'.join(fields)
. This means that self.headers.type
can never be None
.
So, by inspecting the code, I can't figure out how the bug you're reporting happened. I'd prefer to fix its root cause rather than its symptom. For this reason, I'm not eager to blindly commit your suggestion.
Could you check with your browser's inspector which AJAX requests trigger the bug, and which headers they contain exactly ? If we can reproduce the problem, it will be easier to understand its cause.
Per our standard procedures, I'm going to close this ticket as "needing more information", since I don't have enough data to reproduce the problem. Could you add more information about the problematic requests and reopen it? Thank you!
On a related note, MultiPartParser uses this code:
content_type = META.get('HTTP_CONTENT_TYPE', META.get('CONTENT_TYPE', '')) if not content_type.startswith('multipart/'): ...
We may have a small inconsistency here.
follow-up: 4 comment:3 by , 13 years ago
Cc: | added |
---|---|
Resolution: | needsinfo |
Status: | closed → reopened |
Hi!
We had the same problem with a Django instance running inside mod_python (yes, I know mod_python is bad, it's a client's server). I think it happens with a custom iPhone client. Here's the traceback:
Traceback: File "/var/sites/bcl/PYTHON_ENV/lib/python2.5/site-packages/django/core/handlers/base.py" in get_response 111. response = callback(request, *callback_args, **callback_kwargs) File "/var/sites/bcl/main/api.py" in inner 17. token = request.GET.get("authtoken", request.POST.get("authtoken")) File "/var/sites/bcl/PYTHON_ENV/lib/python2.5/site-packages/django/core/handlers/modpython.py" in _get_post 101. self._load_post_and_files() File "/var/sites/bcl/PYTHON_ENV/lib/python2.5/site-packages/django/http/__init__.py" in _load_post_and_files 270. if self.META.get('CONTENT_TYPE', '').startswith('multipart'): Exception Type: AttributeError at /api/events/log/ Exception Value: 'NoneType' object has no attribute 'startswith'
If you want to test it, you could try telnetting a POST response, something like "telnet localhost 8000", then copy-paste
POST / HTTP/1.0 Content-length: 17 query=1234
comment:4 by , 13 years ago
Replying to olau:
Hi!
We had the same problem with a Django instance running inside mod_python
What versions of Django and Python are you using?
comment:6 by , 13 years ago
Triage Stage: | Unreviewed → Design decision needed |
---|
PEP 333 (WSGI spec):
CONTENT_TYPE The contents of any Content-Type fields in the HTTP request. May be empty or absent.
So this is definitively a bug in mod_python
. We are supposed to officially support it until 1.4, but I don't think this is worth it.
comment:7 by , 13 years ago
Huh? Is mod_python implementing WSGI? I thought it was using its own protocol.
Why don't you think a one-line bug fix is worth it? Some people may be stuck on mod_python for some years to come.
comment:8 by , 13 years ago
Cc: | added |
---|
comment:9 by , 13 years ago
Just had a similar problem myself, and I suspect it might have the same root problem. I hate to suggest a workaround for things, but for anyone else who has a similar problem, you might be able to directly specify the CONTENT-TYPE in your ajax request. I don't know why it wasn't sending it by default as 'application/x-www-form-urlencoded' as the documentation says it does (http://api.jquery.com/jQuery.ajax/) so I ended up explicitly adding it in the ajax function call. Example:
$.ajax({ type: 'POST', url: 'your url', success: function(data){ // function to call on success }, dataType: 'text', contentType: 'application/x-www-form-urlencoded', });
comment:10 by , 12 years ago
Cc: | added |
---|---|
Version: | 1.3 → 1.4 |
This same thing happens in 1.4:
File "/usr/local/lib/Django1.4/django/core/handlers/modpython.py", line 56, in _get_request self._request = datastructures.MergeDict(self.POST, self.GET) File "/usr/local/lib/Django1.4/django/core/handlers/modpython.py", line 69, in _get_post self._load_post_and_files() File "/usr/local/lib/Django1.4/django/http/_init_.py", line 353, in _load_post_and_files if self.META.get('CONTENT_TYPE', '').startswith('multipart'): AttributeError: 'NoneType' object has no attribute 'startswith' Request repr() unavailable.
You can easily test it by writing a test that sends a POST without the CONTENT_TYPE header:
def test_missing_content_type(self): // Will throw an exception: response = self.client.post('/url/', {}, HTTP_CONTENT_TYPE=None, follow=True)
comment:11 by , 12 years ago
For master, the question is solved by the removal of mod_python. On 1.4, the correct fix would be to change ModPythonRequest._get_meta
and replace self._req.headers_in.get('content-type')
by self._req.headers_in.get('content-type', '')
. I think that this is a safe bug fix, but won't decide until other committers approve it.
comment:12 by , 12 years ago
I agree that this is only a 1.4 issue - however if modpython is in fact passing in a defined content-type of None, then what we actually need is: self._req.headers_in.get('content-type', '') or ''
since the key exists in this case.
comment:13 by , 12 years ago
Status: | reopened → new |
---|
comment:14 by , 12 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
Since 1.4 is now is security-fixes-only mode, this is moot.
Improved formatting (please use preview).