PDA

Просмотр полной версии : [Delphi] Winsock 2.0; multipart/form-data


RedFern.89
25.05.2010, 00:05
пытался отправить граффити вконтакт по сокетам.. как составить правильно запрос?

вот пример запроса, который был переснят с ВК через CommView.


var
afile, signature, boundary,
cookie, url, Headers, ret,
multi, _post : string;
begin
AFile := 'd:\~tmpPic.png';
// Создаем сигнатуру файла по формуле file -> content -> Base64 -> Copy 1024 bytes -> MD5
Signature := StrTobase64(file_get_contents(AFile), 0); // Получаем контент и кодируем в base64
Signature := Copy(Signature, 0, 1024); // Копируем первые 1024 байта
Signature := GetMD5(Signature); // Хэшируем в MD5

url := 'http://vkontakte.ru/graffiti.php?to_id=46405451&group_id=0';
cookie := 'remixsid=куки; remixchk=5';
boundary := '----OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST';

Headers :=
'POST /graffiti.php?to_id=46405451&group_id=0 HTTP/1.0' + #13#10 +
'User-Agent: Mozilla/4.8 [en](Windows NT 5.0; U)' + #13#10 +
'Accept: Accept: text/html;q=0.9,*/*;q=0.8' + #13#10 +
'Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7' + #13#10 +
'Accept-Language: ru,en-us;q=0.7,en;q=0.3' + #13#10 +
'Connection: close' + #13#10 +
'Referer: http://vkontakte.ru/graffiti.swf?12' + #13#10 +
'Host: ' + GetHost(url) + #13#10 +
'Cookie: ' + cookie + #13#10 +
'Content-Length: con-len' + #13#10 +
'Content-Type: multipart/form-data; boundary=' + boundary + #13#10#13#10;

multi :=
boundary + #13#10 +
'Content-Disposition: form-data; name="Signature"' + #13#10#13#10 +
signature + #13#10 + boundary + #13#10 +
'Content-Disposition: form-data; name="Filedata"; filename="graffiti.png"' + #13#10 +
'Content-Type: image/png' + #13#10#13#10 +
file_get_contents(AFile) + #13#10#13#10 + boundary;

Headers := StringReplace(Headers, 'con-len', IntToStr(Length(multi)), []);

_post := headers + multi;

send_packs(GetIPAddress(GetHost(url)), 80, _post, ret);

memo2.Text := _post;
memo1.Text := ret;
end;


сервак ответил мне на это таким текстом:


HTTP/1.1 302 Found
Server: nginx/0.7.59
Date: Mon, 24 May 2010 20:03:09 GMT
Content-Type: text/html; charset=windows-1251
Connection: close
X-Powered-By: PHP/5.2.6-1+lenny3
Pragma: no-cache
Cache-control: no-store
Location: graffiti.php?act=last
Vary: Accept-Encoding
Content-Length: 0


я перешел по локации, пришедшей мне в заголовках ответа: http://vkontakte.ru/graffiti.php?act=last и у меня открылся рисовальщик граффити вместо нужной страницы с кнопкой отправить.. что не так составленно в запросе?

Chrome~
25.05.2010, 00:47
Если меня не изменяет память, то везде должно быть не
boundary + #13#10
а
'--' + boundary + #13#10
А в самом конце не:
#13#10#13#10 + boundary
а
#13#10 + '--' + boundary + '--' + #13#10

Возможно присутствую еще какие-то незначительные ошибки.

Также, этот код относится к не наилучшему стилю:Headers := StringReplace(Headers, 'con-len', IntToStr(Length(multi)), []);

Это нельзя использовать в String:
file_get_contents(AFile);

RedFern.89
25.05.2010, 01:17
вот запрос выдранный из graffiti.swf


POST /graffiti.php?to_id=52505311&group_id=0 HTTP/1.0
Connection: close
Content-Type: multipart/form-data; boundary=----OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST
Content-Length: 18773
Host: vkontakte.ru
Accept: text/html;q=0.9,*/*;q=0.8
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Accept-Language: ru,en-us;q=0.7,en;q=0.3
User-Agent: Mozilla/4.8 [ru](Windows NT 5.0; U)
Cookie: remixsid=cookies; remixchk=5

------OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST
Content-Disposition: form-data; name="Signature"

a48e6e3b4b07f8e5a668ac2742998c42
------OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST
Content-Disposition: form-data; name="Filedata"; filename="d:\~tmpPic.png"
Content-Type: image/png

тело файла

------OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST--

Chrome~
25.05.2010, 01:33
вот запрос выдранный из graffiti.swf


POST /graffiti.php?to_id=52505311&group_id=0 HTTP/1.0
Connection: close
Content-Type: multipart/form-data; boundary=----OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST
Content-Length: 18773
Host: vkontakte.ru
Accept: text/html;q=0.9,*/*;q=0.8
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Accept-Language: ru,en-us;q=0.7,en;q=0.3
User-Agent: Mozilla/4.8 [ru](Windows NT 5.0; U)
Cookie: remixsid=cookies; remixchk=5

------OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST
Content-Disposition: form-data; name="Signature"

a48e6e3b4b07f8e5a668ac2742998c42
------OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST
Content-Disposition: form-data; name="Filedata"; filename="d:\~tmpPic.png"
Content-Type: image/png

тело файла

------OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST--

Ну так ты присмотрись к этому рядку:
Content-Type: multipart/form-data; boundary=----OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST
и этому
------OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST
Content-Disposition: form-data; name="Signature"

RedFern.89
25.05.2010, 01:35
и реально)) Спасибо )) с этими минусами (тире) все мозги кипят просто уже! оо :o :o

Berman
25.05.2010, 13:11
Разве нет api метода для загрузки граффити?

RedFern.89
25.05.2010, 13:30
еть! но всеравно ты заливаешь файл на сервер. Дело не в сложности использования методов (api или стандартный вк метод). Дело в основе

Jingo Bo
26.05.2010, 02:04
Это нельзя использовать в String
Гыгы, можно, результат будет тот же:) (P.S. Путаешь стандартные null-terminated строки, у Delphi свой формат, к сожалению)

Chrome~
26.05.2010, 09:11
Гыгы, можно, результат будет тот же:) (P.S. Путаешь стандартные null-terminated строки, у Delphi свой формат, к сожалению)
Я не исключаю что можно использовать AnsiString, но советую использовать либо array of char, либо array of byte. Так будет более правильно.

Gar|k
27.05.2010, 23:18
RedFern.89 мне кажется через пару лет у тебя будет программа с интерфейсом и функциями вконтакта которая будет отправлять HTTP запросы на сервер вконтакта напрямую, а не через wеb интерфейс...

RedFern.89 учи js php mySQL и переходи уже на веб кодинг )

RedFern.89
27.05.2010, 23:24
js и php я чутка и так знаю =) на уровне не новичка так скажем))

RedFern.89
28.05.2010, 01:52
Дабы не плодить кучу тем по моим вопросам, задам вопрос тут. Есть 1 функция и одна процедура. Обе взаимосвязанны. Называются Get и Redirect. Думаю человек, знающий протокол HTTP поймет, что за функции. Допустим при выполнении функции GET произошло 2 редиректа. Как сделать так, что бы функция GET закончила свое выполнение, до тех пор, пока все редиректы не закончатся? т.е. вернула страницу конечного редиректа. В моем же случае функция GET возврщает код 1й страницы, а нужно той страницы, на которую произошла переадресация. Получается так, что функция get работает дальше и грузит все страницы, но в том коде, в котором она выполняется она отдала код 1й страницы и все. Привожу коды обеих процедур:


// ---- Обрабатываем перенаправление ----
procedure THTTPCli.Redirect(const AData, AHost: string);
var
Location : string;
begin
Location := AData;
Location := Copy(Location, Pos('Location:', Location) +10, Length(Location));
Delete(Location, Pos(#13, Location), Length(Location));

// Проверка локаций и исправление
If Location[1] = '/' Then Get(AHost + Location);

If (Location[1] <> '/') And (Pos('http://', location) = 0) Then
begin
Location := '/' + Location;
Get('http://' + AHost + Location);
end;

If Pos('http://', Location) <> 0 then
begin
Location := Copy(Location, Length(GetHost(Location)) +8, Length(Location));
Get(Location);
end;

end;

// ---- Отправка GET-запроса ---- ;overload
function THTTPCli.Get(const AURL: string): string;
var
Head : string;
Host : string;
urlObj : string;
begin
{ Парсим url }
urlObj := AURL;
urlObj := Copy(urlObj, Length(GetHost(urlObj)) +8, Length(urlObj));
Host := GetHost(AURL);

// Составляем заголовок без куков
Head := 'GET ' + urlObj + ' HTTP/1.1' + crlf +
'User-Agent: Mozilla/4.8 [en](Windows NT 5.0; U)' + crlf +
'Connection: close' + crlf +
'Host: ' + Host + crlf + crlf;

// А если таковые имеются, прибавляем их к заголовку
If Length(_cookie) <> 0 Then
begin
Head := 'GET ' + urlObj + ' HTTP/1.1' + crlf +
'User-Agent: Mozilla/4.8 [en](Windows NT 5.0; U)' + crlf +
'Connection: close' + crlf +
'Cookie: ' + _cookie + crlf +
'Host: ' + Host + crlf + crlf;
end;
// Отсылаем запрос
SendRequest(Host, 80, Head, Result);

// Если сервер сказал 302, переходим по сказанной локации
If Pos('302', Result) <> 0 then
begin
Redirect(Result, Host);
end;
end;


блин как запарился уже. Извините за офтоп и кучу всем давно надоевшим вопросам.

GhostOnline
28.05.2010, 08:54
If Pos('302', Result) <> 0 then
Хм, если на странице просто попадется "302" то это будет считаться как редирект?
Вообще, если я правильно тебя понял то тебе надо просто организовать цикл.
Что-то типа:
while Pos('302', Result) <> 0 do
Redirect(Result, Host);

RedFern.89
28.05.2010, 12:56
Хм, если на странице просто попадется "302" то это будет считаться как редирект?
Вообще, если я правильно тебя понял то тебе надо просто организовать цикл.
Что-то типа:
while Pos('302', Result) <> 0 do
Redirect(Result, Host);


и в твоем случае он будет все время грузить последнюю страницу... не вариант

GhostOnline
28.05.2010, 16:37
Так епт сделай Redirect функцией, которая например возвращает true если редирект был и false если не был
Вообше, имхо извращенное у тебя распределение по методам

RedFern.89
28.05.2010, 20:57
GhostOnline, пример в студию!!!

Chrome~
28.05.2010, 21:10
Нужно чтобы твоя функция Redirect возвращала тело новой скачанной страницы. Тогда можно реализовать цикл, который написал GhostOnline.

RedFern.89
29.05.2010, 02:30
вообщето цикл так и висит, потому-что он читает код первого ответа и все...

GhostOnline
29.05.2010, 16:39
Пипец..Ты зациклил 2 метода, в первом вызываешь второй, во втором первый, и т.д.. еще удивляешься почему возвращается "код певрого ответа"
Get - функция, она возвращает result.
Далее если ответ 302 то ты вызываешь процедуру Redirect и ей передаешь resault.
Процедура по определению ничего не возвращает, и с result ничего не делает, потому что:
1. Ты в процедуре не оперируешь параметром AData
2. Даже если бы захотел оперировать, то значение все равно бы не изменилось, ибо: const AData
// Если сервер сказал 302, переходим по сказанной локации
If Pos('302', Result) <> 0 then
begin
Redirect(Result, Host);
end;

Переходить то ты переходишь, но с какого х** result должна измениться если ты в этой функции с ней ничего больше не делаешь?

PS Мораль такова: вызываемая подпрограмма не может изменять результат той подпрограммы в которой она была вызвана, за исключением способа передачи по ссылке(var)

RedFern.89
31.05.2010, 00:23
уважаемый GhostOnline, я вас понел)) спасибо большое))