Problems PUTting binary data to Django
I am trying to build a RESTful api with Django to share mp3s -- right up front: it's a toy app, never going into production, so it doesn't need to scale or worry (I hope) about copyright devils. My problem now is that I have a Django view that I want to be the endpoint for HTTP PUT requests. The headers of the PUT will contain the metadata, and the body will exclusively be the binary.
Here's the actual view that I am (trying) to hit. Please note that logging indicates that cont开发者_运维知识库rol flow never enters the put() method, which I believe is correct, if not especially robust:
class UserSong(RESTView):
logging.debug('entering UserSong.put')
def put(self, request, username=''):
if request.META['Content-Type'] != 'octet/stream':
raise Http400()
title = request.META['X-BD-TITLE'] if 'X-BD-TITLE' in request.META else 'title unknown'
artist = request.META['X-BD-ARTIST'] if 'X-BD-ARTIST' in request.META else 'artist unknown'
album = request.META['X-BD-ALBUM'] if 'X-BD-ALBUM' in request.META else 'album unknown'
song_data = b6decode(request.raw_post_data)
song = Song(title=title, artist=artist, playcount=playcount, is_sample=is_sample, song_data=song_data, album=album)
song.save()
return HttpResponse('OK', 'text/plain' , 201)
def __call__(self, request, *args, **kwargs):
logging.basicConfig(filename=LOGFILE,level=logging.DEBUG)
try:
if request.method == 'DELETE':
return self.delete(request, *args, **kwargs)
elif request.method == 'GET':
return self.get(request, *args, **kwargs)
elif request.method == 'POST':
return self.post(request, *args, **kwargs)
elif request.method == 'PUT':
return self.put(request, *args, **kwargs)
except:
raise Http404()
In testing this, I was able to get unittests to pass using Django's unittesting framework, but I do not trust that it was accurately mimicking Real Life. So, I cracked open httplib, and constructed a PUT my own self. This is that code, which I executed interactively:
>>>method = 'PUT'
>>>url = 'accounts/test/songs/'
>>>f = open('/Users/bendean/Documents/BEARBOT.mp3')
>>>data = f.read()
>>>body = data
>>>headers = {'X-BD-ARTIST' : 'BEARBOT' , 'X-BD-ALBUM':'','X-BD-TITLE':'LightningSPRKS'}
>>>headers['CONTENT-TYPE'] = 'octet/stream'
>>>import httplib
>>>c = httplib.HTTPConnection('localhost:8000')
>>>c.request(method, url, body, headers)
the response I get is not pretty
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 880, in request
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 914, in _send_request
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 719, in send
File "<string>", line 1, in sendall
error: [Errno 54] Connection reset by peer
though sometimes I get
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 880, in request
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 914, in _send_request
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 719, in send
File "<string>", line 1, in sendall
error: [Errno 32] Broken pipe
I'm fairly confident that my URLs are working (the GET handler is doing just fine, thank you). Logging indicates that the request is not actually making it to the handler code.
googling around brings me to issue trackers suggesting that the issue is in httplib's handling of an error while uploading a big file (this one is 3.7 mb).
So, I am not ashamed to admit that I am out of my depth here-- how can I determine what is causing the error? Am I formatting my request properly (p.s. I also tried b64encoding the body, with the same results)?. In a larger sense, is what I'm doing (to test, not in life) reasonable? Does it have anything to do with configurable settings on the dev server? Would these problems go away if I were to try putting this on Apache? Your help is very much appreciated.
It does appear that the issue is in the dev server's handling of large requests. After deploying to apache with mod_wsgi, this problem goes away. Still lots of open questions for me about RESTful file uploads...
精彩评论