[Delphi] Winsock 2.0; multipart/form-data

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by RedFern.89, 25 May 2010.

  1. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    557
    Likes Received:
    45
    Reputations:
    0
    пытался отправить граффити вконтакт по сокетам.. как составить правильно запрос?

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

    Code:
    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
    -Length0
    я перешел по локации, пришедшей мне в заголовках ответа: http://vkontakte.ru/graffiti.php?act=last и у меня открылся рисовальщик граффити вместо нужной страницы с кнопкой отправить.. что не так составленно в запросе?
     
    #1 RedFern.89, 25 May 2010
    Last edited: 25 May 2010
  2. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    937
    Likes Received:
    162
    Reputations:
    27
    Если меня не изменяет память, то везде должно быть не
    Code:
    boundary + #13#10
    а
    Code:
    '--' + boundary + #13#10
    А в самом конце не:
    Code:
    #13#10#13#10 + boundary
    а
    Code:
    #13#10 + '--' + boundary + '--' + #13#10
    Возможно присутствую еще какие-то незначительные ошибки.

    Также, этот код относится к не наилучшему стилю:
    Code:
    Headers := StringReplace(Headers, 'con-len', IntToStr(Length(multi)), []);
    Это нельзя использовать в String:
    Code:
    file_get_contents(AFile);
     
    #2 Chrome~, 25 May 2010
    Last edited: 25 May 2010
  3. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    557
    Likes Received:
    45
    Reputations:
    0
    вот запрос выдранный из graffiti.swf

    Code:
    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--
    
     
  4. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    937
    Likes Received:
    162
    Reputations:
    27
    Ну так ты присмотрись к этому рядку:
    Code:
    Content-Type: multipart/form-data; boundary=[B][COLOR=Red]----[/COLOR][/B]OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST
    и этому
    Code:
    [B][COLOR=Lime]--[/COLOR][COLOR=Red]----[/COLOR][/B]OLEG-ANDREEV-PAVEL-DUROV-GRAFFITI-POST
    Content-Disposition: form-data; name="Signature"
     
    1 person likes this.
  5. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    557
    Likes Received:
    45
    Reputations:
    0
    и реально)) Спасибо )) с этими минусами (тире) все мозги кипят просто уже! оо :eek: :eek:
     
    #5 RedFern.89, 25 May 2010
    Last edited: 25 May 2010
  6. Refqs

    Refqs Banned

    Joined:
    20 Feb 2010
    Messages:
    139
    Likes Received:
    56
    Reputations:
    27
    Разве нет api метода для загрузки граффити?
     
  7. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    557
    Likes Received:
    45
    Reputations:
    0
    еть! но всеравно ты заливаешь файл на сервер. Дело не в сложности использования методов (api или стандартный вк метод). Дело в основе
     
  8. Jingo Bo

    Jingo Bo Member

    Joined:
    25 Oct 2009
    Messages:
    368
    Likes Received:
    51
    Reputations:
    7
    Гыгы, можно, результат будет тот же:) (P.S. Путаешь стандартные null-terminated строки, у Delphi свой формат, к сожалению)
     
  9. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    937
    Likes Received:
    162
    Reputations:
    27
    Я не исключаю что можно использовать AnsiString, но советую использовать либо array of char, либо array of byte. Так будет более правильно.
     
    #9 Chrome~, 26 May 2010
    Last edited: 26 May 2010
  10. Gar|k

    Gar|k Moderator

    Joined:
    20 Mar 2009
    Messages:
    1,166
    Likes Received:
    266
    Reputations:
    82
    RedFern.89 мне кажется через пару лет у тебя будет программа с интерфейсом и функциями вконтакта которая будет отправлять HTTP запросы на сервер вконтакта напрямую, а не через wеb интерфейс...

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

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    557
    Likes Received:
    45
    Reputations:
    0
    js и php я чутка и так знаю =) на уровне не новичка так скажем))
     
  12. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    557
    Likes Received:
    45
    Reputations:
    0
    ну звиздец какойто просто...

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

    Code:
    // ---- Обрабатываем перенаправление ----
    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;
    
    блин как запарился уже. Извините за офтоп и кучу всем давно надоевшим вопросам.
     
    #12 RedFern.89, 28 May 2010
    Last edited: 28 May 2010
  13. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Хм, если на странице просто попадется "302" то это будет считаться как редирект?
    Вообще, если я правильно тебя понял то тебе надо просто организовать цикл.
    Что-то типа:
    while Pos('302', Result) <> 0 do
    Redirect(Result, Host);
     
  14. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    557
    Likes Received:
    45
    Reputations:
    0

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

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Так епт сделай Redirect функцией, которая например возвращает true если редирект был и false если не был
    Вообше, имхо извращенное у тебя распределение по методам
     
  16. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    557
    Likes Received:
    45
    Reputations:
    0
    GhostOnline, пример в студию!!!
     
  17. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    937
    Likes Received:
    162
    Reputations:
    27
    Нужно чтобы твоя функция Redirect возвращала тело новой скачанной страницы. Тогда можно реализовать цикл, который написал GhostOnline.
     
  18. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    557
    Likes Received:
    45
    Reputations:
    0
    вообщето цикл так и висит, потому-что он читает код первого ответа и все...
     
  19. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Пипец..Ты зациклил 2 метода, в первом вызываешь второй, во втором первый, и т.д.. еще удивляешься почему возвращается "код певрого ответа"
    Get - функция, она возвращает result.
    Далее если ответ 302 то ты вызываешь процедуру Redirect и ей передаешь resault.
    Процедура по определению ничего не возвращает, и с result ничего не делает, потому что:
    1. Ты в процедуре не оперируешь параметром AData
    2. Даже если бы захотел оперировать, то значение все равно бы не изменилось, ибо: const AData
    Переходить то ты переходишь, но с какого х** result должна измениться если ты в этой функции с ней ничего больше не делаешь?

    PS Мораль такова: вызываемая подпрограмма не может изменять результат той подпрограммы в которой она была вызвана, за исключением способа передачи по ссылке(var)
     
    #19 GhostOnline, 29 May 2010
    Last edited: 29 May 2010
    1 person likes this.
  20. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    557
    Likes Received:
    45
    Reputations:
    0
    уважаемый GhostOnline, я вас понел)) спасибо большое))