Skip to content
This repository has been archived by the owner on Nov 25, 2022. It is now read-only.

Commit

Permalink
Fixed issues with uploading files
Browse files Browse the repository at this point in the history
  • Loading branch information
coordt committed May 14, 2015
1 parent a08842f commit 0c2528f
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 79 deletions.
83 changes: 42 additions & 41 deletions apps/djangopypi/http.py
Expand Up @@ -20,65 +20,66 @@ def parse_distutils_request(request):
""" This is being used because the built in request parser that Django uses,
django.http.multipartparser.MultiPartParser is interperting the POST data
incorrectly and/or the post data coming from distutils is invalid.
One portion of this is the end marker: \r\n\r\n (what Django expects)
versus \n\n (what distutils is sending).
One portion of this is the end marker: \r\n\r\n (what Django expects)
versus \n\n (what distutils is sending).
"""

try:
sep = request.raw_post_data.splitlines()[1]
except:
raise ValueError('Invalid post data')


request.POST = QueryDict('',mutable=True)

sep = request.body.splitlines()[1]
request.POST = QueryDict('', mutable=True)

try:
request._files = MultiValueDict()
except Exception, e:
except Exception:
pass

for part in filter(lambda e: e.strip(), request.raw_post_data.split(sep)):

for part in filter(lambda e: e.strip(), request.body.split(sep)):

try:
header, content = part.lstrip().split('\n',1)
except Exception, e:
header, content = part.lstrip().split('\n', 1)
except Exception:
continue

if content.startswith('\n'):
content = content[1:]

if content.endswith('\n'):
content = content[:-1]

headers = parse_header(header)

if "name" not in headers:
continue

if "filename" in headers:
dist = TemporaryUploadedFile(name=headers["filename"],
size=len(content),
content_type="application/gzip",
charset='utf-8')
dist.write(content)
dist.seek(0)
request.FILES.appendlist(headers['name'], dist)
else:
request.POST.appendlist(headers["name"],content)

try:
if content.startswith('\n'):
content = content[1:]

if content.endswith('\n'):
content = content[:-1]

headers = parse_header(header)

if "name" not in headers:
continue

if "filename" in headers:
dist = TemporaryUploadedFile(name=headers["filename"],
size=len(content),
content_type="application/gzip",
charset='utf-8')
dist.write(content)
dist.seek(0)
request.FILES.appendlist(headers['name'], dist)
else:
request.POST.appendlist(headers["name"], content)
except Exception as e:
print e
return


def parse_header(header):
headers = {}
for kvpair in filter(lambda p: p,
map(lambda p: p.strip(),
header.split(';'))):
try:
key, value = kvpair.split("=",1)
key, value = kvpair.split("=", 1)
except ValueError:
continue
headers[key.strip()] = value.strip('"')

return headers


def login_basic_auth(request):
authentication = request.META.get("HTTP_AUTHORIZATION")
Expand Down
15 changes: 15 additions & 0 deletions apps/djangopypi/middleware.py
@@ -0,0 +1,15 @@
from django.conf import settings


class ConsoleExceptionMiddleware:
def process_exception(self, request, exception):
if not settings.DEBUG:
return
import traceback
import sys
exc_info = sys.exc_info()
print "######################## Exception #############################"
print '\n'.join(traceback.format_exception(*(exc_info or sys.exc_info())))
print "################################################################"
#print repr(request)
#print "################################################################"
67 changes: 29 additions & 38 deletions apps/djangopypi/views/distutils.py
@@ -1,35 +1,30 @@
import os,re
import os
from logging import getLogger

from django.conf import settings
from django.db import transaction
from django.http import *
from django.http import (HttpResponseBadRequest, HttpResponseForbidden,
HttpResponseServerError, HttpResponse)
from django.utils.translation import ugettext_lazy as _
from django.utils.datastructures import MultiValueDict
from django.contrib.auth import login

from djangopypi import settings
from djangopypi.decorators import basic_auth
from djangopypi.forms import PackageForm, ReleaseForm
from djangopypi.models import Package, Release, Distribution, Classifier



log = getLogger('djangopypi.views.distutils')

ALREADY_EXISTS_FMT = _(
"A file named '%s' already exists for %s. Please create a new release.")


@basic_auth
@transaction.commit_manually
def register_or_upload(request):
if request.method != 'POST':
transaction.rollback()
return HttpResponseBadRequest('Only post requests are supported')

name = request.POST.get('name',None).strip()
name = request.POST.get('name', None).strip()

if not name:
transaction.rollback()
return HttpResponseBadRequest('No package name specified')

try:
Expand All @@ -39,36 +34,33 @@ def register_or_upload(request):
package.owners.add(request.user)

if (request.user not in package.owners.all() and
request.user not in package.maintainers.all()):
request.user not in package.maintainers.all()):

transaction.rollback()
return HttpResponseForbidden('You are not an owner/maintainer of %s' % (package.name,))

version = request.POST.get('version',None).strip()
version = request.POST.get('version', None).strip()
metadata_version = request.POST.get('metadata_version', None).strip()

if not version or not metadata_version:
transaction.rollback()
return HttpResponseBadRequest('Release version and metadata version must be specified')

if not metadata_version in settings.DJANGOPYPI_METADATA_FIELDS:
transaction.rollback()
if metadata_version not in settings.METADATA_FIELDS:
return HttpResponseBadRequest('Metadata version must be one of: %s'
(', '.join(settings.DJANGOPYPI_METADATA_FIELDS.keys()),))
(', '.join(settings.METADATA_FIELDS.keys()),))

release, created = Release.objects.get_or_create(package=package,
version=version)

if (('classifiers' in request.POST or 'download_url' in request.POST) and
metadata_version == '1.0'):
metadata_version == '1.0'):
metadata_version = '1.1'

release.metadata_version = metadata_version

fields = settings.DJANGOPYPI_METADATA_FIELDS[metadata_version]
fields = settings.METADATA_FIELDS[metadata_version]

if 'classifiers' in request.POST:
request.POST.setlist('classifier',request.POST.getlist('classifiers'))
request.POST.setlist('classifier', request.POST.getlist('classifiers'))

release.package_info = MultiValueDict(dict(filter(lambda t: t[0] in fields,
request.POST.iterlists())))
Expand All @@ -78,39 +70,38 @@ def register_or_upload(request):
filter(lambda v: v != 'UNKNOWN', value))

release.save()
if not 'content' in request.FILES:
transaction.commit()
if 'content' not in request.FILES:
return HttpResponse('release registered')

uploaded = request.FILES.get('content')

for dist in release.distributions.all():
if os.path.basename(dist.content.name) == uploaded.name:
""" Need to add handling optionally deleting old and putting up new """
transaction.rollback()
return HttpResponseBadRequest('That file has already been uploaded...')

md5_digest = request.POST.get('md5_digest','')
md5_digest = request.POST.get('md5_digest', '')

try:
new_file = Distribution.objects.create(release=release,
content=uploaded,
filetype=request.POST.get('filetype','sdist'),
pyversion=request.POST.get('pyversion',''),
uploader=request.user,
comment=request.POST.get('comment',''),
signature=request.POST.get('gpg_signature',''),
md5_digest=md5_digest)
except Exception, e:
transaction.rollback()
Distribution.objects.create(
release=release,
content=uploaded,
filetype=request.POST.get('filetype', 'sdist'),
pyversion=request.POST.get('pyversion', ''),
uploader=request.user,
comment=request.POST.get('comment', ''),
signature=request.POST.get('gpg_signature', ''),
md5_digest=md5_digest)
except Exception as e:
log.exception('Failure when storing upload')
log.exception(e.msg)
print e
return HttpResponseServerError('Failure when storing upload')

transaction.commit()

return HttpResponse('upload accepted')


def list_classifiers(request, mimetype='text/plain'):
response = HttpResponse(mimetype=mimetype)
response.write(u'\n'.join(map(lambda c: c.name,Classifier.objects.all())))
response.write(u'\n'.join(map(lambda c: c.name, Classifier.objects.all())))
return response
1 change: 1 addition & 0 deletions settings.py
Expand Up @@ -122,6 +122,7 @@
GOOGLE_ANALYTICS_PROPERTY_ID = 'UA-8352901-3'

MIDDLEWARE_CLASSES = [
'djangopypi.middleware.ConsoleExceptionMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
Expand Down

0 comments on commit 0c2528f

Please sign in to comment.