Загрузка файлов на http сервер выполняется методом POST. Большие файлы передаваются несколькими запросами.
В качестве url POST-запроса указывается скрипт-обработчик, в нашем случае скрипт wsgi. Обработчик должен брать на себя полностью управление загрузкой - контроль типа файла, размера, количества загружаемых файлов.
В принципе, управление загрузкой файлов на сервер можно управлять без подключения дополнительных модулей, напрямую обращаясь к переменной окружения environ['wsgi.input']. Но удобнее воспользоваться модулем cgi. Ниже приведен пример функции, которая анализирует запрос с переданными для загрузки файлами и возвращает информацию об этих файлах. При этом загружать сами файлы пока не будем
import cgi
def application(environ, start_response):
formdata = cgi.FieldStorage(environ=environ, fp=environ['wsgi.input'])
l=formdata.list
output= 'Files count: %d. Size all files: %d\r\n' % (len(l), formdata.length)
# отображаемый размер будет на пару сотен байт больше суммарного размера файлов (это заголовки)
for i in xrange(len(l)):
output+='Filename: %s, type: %s\r\n' % (l[i].filename, l[i].type)
status = '200 OK'
response_headers = [
('Content-Type', 'text/plain'),
('Content-Length', str(len(output)))
]
start_response(status, response_headers)
return [output]
Проследить как работает скрипт можно, например, воспользовавшись утилитой curl
curl -F name1=@test1.txt -F name2=@test2.txt http://tests/ul
Для сохранения переданных файлов можно применить функцию приведенную ниже. В функцию добавлены следующие типы проверок: * по количеству загружаемых файлов * по размеру каждого загружаемого файла * по типу файла (по его расширению)
from tempfile import TemporaryFile
import cgi
def application(environ, start_response):
output=upload(environ)
status = '200 Ok'
response_headers = [
('Content-Type', 'text/plain'),
('Content-Length', str(len(output)))
]
start_response(status, response_headers)
return [output]
def upload(environ):
MAX_COUNT_FILES=2
MAX_FILE_SIZE=2024*2
EXTENSION=['txt','json', 'csv']
formdata = cgi.FieldStorage(environ=environ, fp=environ['wsgi.input'])
output=''
files_list=formdata.list
count=len(files_list)
# проверка по количеству
if count>MAX_COUNT_FILES:
output='\nAttempt upload %d files. Max count - %d. Files not uploaded\n' % (count, MAX_COUNT_FILES)
return output
for i in xrange(count):
# проверка по расширению
ext=files_list[i].filename.split('.')[-1]
if ext not in EXTENSION:
output+='File %s has invalid type. Must be %s\n' % (files_list[i].filename, str(EXTENSION))
continue
# проверка по размеру
body=files_list[i].file
body.seek(0, 2)
if body.tell()>MAX_FILE_SIZE:
output+='File %s has large size. Max file size - %d\n' % (files_list[i].filename, MAX_FILE_SIZE)
continue
body.seek(0)
# сохранение во временный файл с дополнительным контролем размера
temp_f = TemporaryFile()
m=MAX_FILE_SIZE
while m > 0:
part = body.read(min(m, 1024*200))
if not part: break
temp_f.write(part)
m -= len(part)
if part:
continue
f=open('/var/www/tests/upload/'+files_list[i].filename,'wb')
temp_f.seek(0)
f.write(temp_f.read())
f.close()
temp_f.close()
output+= 'File %s uploaded\n' % files_list[i].filename
return output