#python #http #google-app-engine
#python #http #google-app-engine
Вопрос:
Я пытаюсь отправить файл в torrage.com из приложения в GAE. файл сохраняется в памяти после получения от пользователя при загрузке.
Я хотел бы иметь возможность опубликовать этот файл, используя API, доступный здесь: http://torrage.com/automation.php но у меня возникли некоторые проблемы с определением того, как должно быть закодировано тело сообщения, максимум, что я получил от API, — это сообщение «файл пуст».
Ответ №1:
Я нахожу документы API torrage в интерфейсе POST (в отличие от SOAP) довольно запутанными и противоречащими образцу кода C, который они также предоставляют. Мне кажется, что в их онлайн-примере PHP post они не отправляют содержимое файла (точно так же, как ответ @kender выше не отправляет его), в то время как они отправляют его в примерах SOAP и в примере C-кода.
Соответствующая часть примера C (как они вычисляют заголовки, к которым вы будете переходить urlfetch.fetch
) является:
snprintf(formdata_header, sizeof(formdata_header) - 1,
"Content-Disposition: form-data; name="torrent"; filename="%s"n"
"Content-Type: " HTTP_UPLOAD_CONTENT_TYPE "n"
"n",
torrent_file);
http_content_len = 2 strlen(content_boundary) 1 strlen(formdata_header) st.st_size 1 2 strlen(content_boundary) 3;
LTdebug("http content len %un", http_content_len);
snprintf(http_req, sizeof(http_req) - 1,
"POST /%s HTTP/1.1n"
"Host: %sn"
"User-Agent: libtorrage/" LTVERSION "n"
"Connection: closen"
"Content-Type: multipart/form-data; boundary=%sn"
"Content-Length: %un"
"n",
cache_uri, cache_host, content_boundary, http_content_len);
«application/x-bittorrent» — это HTTP_UPLOAD_CONTENT_TYPE
. st.st_size
— это количество байтов в буфере памяти со всеми данными файла (пример C считывает эти данные из файла, но не имеет значения, как вы получили их в память, если вы знаете их размер). content_boundary
это строка, которой НЕТ в содержимом файла, они создают ее как, "---------------------------%u%uLT"
причем каждое %u
из них заменяется случайным числом (повторяется до тех пор, пока эта строка не наткнется на два случайных числа, которые делают ее отсутствующей в файле). Наконец, в теле post (после открытия HTTP-сокета и отправки других заголовков) они пишут следующее:
if (write_error == 0) if (write(sock, "--", 2) <= 0) write_error = 1;
if (write_error == 0) if (write(sock, content_boundary, strlen(content_boundary)) <= 0) write_error = 1;
if (write_error == 0) if (write(sock, "n", 1) <= 0) write_error = 1;
if (write_error == 0) if (write(sock, formdata_header, strlen(formdata_header)) <= 0) write_error = 1;
if (write_error == 0) if (write(sock, filebuf, st.st_size) <= 0) write_error = 1;
if (write_error == 0) if (write(sock, "n--", 3) <= 0) write_error = 1;
if (write_error == 0) if (write(sock, content_boundary, strlen(content_boundary)) <= 0) write_error = 1;
if (write_error == 0) if (write(sock, "--n", 3) <= 0) write_error = 1;
где filebuf
находится буфер с содержимым файла.
Вряд ли это четко и просто, но я надеюсь, что здесь достаточно информации, чтобы выработать способ построения аргументов для a urlfetch.fetch
(создать их для a urllib.urlopen
было бы так же сложно, поскольку проблема заключается в нехватке документации о том, какие именно заголовки и какой контент и как закодированы вам нужны — и эта недостаточно хорошо документированная информация нуждается в обратном проектировании из того, что я здесь представляю, я думаю).
В качестве альтернативы может оказаться возможным взломать запрос SOAP с помощью urlfetch; смотрите Здесь длинный пост Карсона о его попытках, трудностях и успехах в этом вопросе. И удачи!
Ответ №2:
Почему бы просто не использовать модуль Python urllib2 для создания POST-запроса, как показано в примере для PHP. Это было бы что-то вроде этого:
import urrlib, urllib2
data = (
('name', 'torrent'),
('type', 'application/x-bittorrent'),
('file', '/path/to/your/file.torrent'),
)
request = urllib2.urlopen('http://torrage.com/autoupload.php', urllib.urlencode(data))
Комментарии:
1. В App Engine нет файлов, мне нужно использовать то, что у меня есть в памяти, для отправки файла.
2. Поскольку в примере PHP используется некоторая функциональность PHP, которая создает запрос multipart / form-data, не запрос в кодировке формы, который создается в вашем примере.
Ответ №3:
Судя по коду C, он использует формат «multipart / form-data», который очень сложный, и очень легко сделать что-то неправильно. Я бы не стал вручную кодировать текст сообщения подобным образом.
Я использовал функцию из этого блога, и она работала у меня в автономной программе. Возможно, вы захотите попробовать это в app engine,
http://peerit.blogspot.com/2007/07/multipartposthandler-doesnt-work-for.html