Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   С/С++, C#, Delphi, .NET, Asm (https://forum.antichat.xyz/forumdisplay.php?f=24)
-   -   [Delphi] Winsock 2.0; multipart/form-data (https://forum.antichat.xyz/showthread.php?t=206577)

RedFern.89 25.05.2010 00:05

[Delphi] Winsock 2.0; multipart/form-data
 
пытался отправить граффити вконтакт по сокетам.. как составить правильно запрос?

вот пример запроса, который был переснят с ВК через 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;

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

PHP код:

HTTP/1.1 302 Found
Server
nginx/0.7.59
Date
Mon24 May 2010 20:03:09 GMT
Content
-Typetext/htmlcharset=windows-1251
Connection
close
X
-Powered-ByPHP/5.2.6-1+lenny3
Pragma
no-cache
Cache
-controlno-store
Location
graffiti.php?act=last
Vary
Accept-Encoding
Content
-Length

я перешел по локации, пришедшей мне в заголовках ответа: 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

Цитата:

Сообщение от RedFern.89
вот запрос выдранный из 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

Цитата:

Сообщение от Jingo Bo
Гыгы, можно, результат будет тот же:) (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

Цитата:

Сообщение от GhostOnline
Хм, если на странице просто попадется "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, я вас понел)) спасибо большое))


Время: 07:58