delphihttppostrequestwininet

How to send a HTTP POST Request in Delphi using WinInet api


I am trying to make HTTP Requests from Delphi using the WinInet functions.

So far I have:

function request:string;
var
  hNet,hURL,hRequest: HINTERNET;
begin
  hNet := InternetOpen(PChar('User Agent'),INTERNET_OPEN_TYPE_PRECONFIG or INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  if Assigned(hNet) then 
  begin
  try
    hURL := InternetConnect(hNet,PChar('http://example.com'),INTERNET_DEFAULT_HTTP_PORT,nil,nil,INTERNET_SERVICE_HTTP,0,DWORD(0));
    if(hURL<>nil) then
      hRequest := HttpOpenRequest(hURL, 'POST', PChar('param=value'),'HTTP/1.0',PChar(''), nil, INTERNET_FLAG_RELOAD or INTERNET_FLAG_PRAGMA_NOCACHE,0);
    if(hRequest<>nil) then
      HttpSendRequest(hRequest, nil, 0, nil, 0);
    InternetCloseHandle(hNet);
  except
    on E : Exception do
      ShowMessage(E.ClassName+' error raised, with message : '+E.Message);
  end;
  end
end;

But this doesn't do anything (I am sniffing network http traffic to see if it works). I have successfully used InternetOpenURL but I also need to send POST request and that function doesn't do that.

Could someone show me a simple example? The result I want is to get the http response page in a var as string.


Solution

  • I got all the url/filename part messed up with the previous code. I'm using this from Jeff DeVore now and it's working fine:

    function request(const AUrl, AData: AnsiString; blnSSL: Boolean = True): AnsiString;
    var
      aBuffer     : Array[0..4096] of Char;
      Header      : TStringStream;
      BufStream   : TMemoryStream;
      sMethod     : AnsiString;
      BytesRead   : Cardinal;
      pSession    : HINTERNET;
      pConnection : HINTERNET;
      pRequest    : HINTERNET;
      parsedURL   : TStringArray;
      port        : Integer;
      flags       : DWord;
    begin
      ParsedUrl := ParseUrl(AUrl);
    
      Result := '';
    
      pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
    
      if Assigned(pSession) then
      try
        if blnSSL then
          Port := INTERNET_DEFAULT_HTTPS_PORT
        else
          Port := INTERNET_DEFAULT_HTTP_PORT;
        pConnection := InternetConnect(pSession, PChar(ParsedUrl[0]), port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
    
        if Assigned(pConnection) then
        try
          if (AData = '') then
            sMethod := 'GET'
          else
            sMethod := 'POST';
    
          if blnSSL then
            flags := INTERNET_FLAG_SECURE or INTERNET_FLAG_KEEP_CONNECTION
          else
            flags := INTERNET_SERVICE_HTTP;
    
          pRequest := HTTPOpenRequest(pConnection, PChar(sMethod), PChar(ParsedUrl[1]), nil, nil, nil, flags, 0);
    
          if Assigned(pRequest) then
          try
            Header := TStringStream.Create('');
            try
              with Header do
              begin
                WriteString('Host: ' + ParsedUrl[0] + sLineBreak);
                WriteString('User-Agent: Custom program 1.0'+SLineBreak);
                WriteString('Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'+SLineBreak);
                WriteString('Accept-Language: en-us,en;q=0.5' + SLineBreak);
                WriteString('Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7'+SLineBreak);
                WriteString('Keep-Alive: 300'+ SLineBreak);
                WriteString('Connection: keep-alive'+ SlineBreak+SLineBreak);
              end;
    
              HttpAddRequestHeaders(pRequest, PChar(Header.DataString), Length(Header.DataString), HTTP_ADDREQ_FLAG_ADD);
    
              if HTTPSendRequest(pRequest, nil, 0, Pointer(AData), Length(AData)) then
              begin
                BufStream := TMemoryStream.Create;
                try
                  while InternetReadFile(pRequest, @aBuffer, SizeOf(aBuffer), BytesRead) do
                  begin
                    if (BytesRead = 0) then Break;
                    BufStream.Write(aBuffer, BytesRead);
                  end;
    
                  aBuffer[0] := #0;
                  BufStream.Write(aBuffer, 1);
                  Result := PChar(BufStream.Memory);
                finally
                  BufStream.Free;
                end;
              end;
            finally
              Header.Free;
            end;
          finally
            InternetCloseHandle(pRequest);
          end;
        finally
          InternetCloseHandle(pConnection);
        end;
      finally
        InternetCloseHandle(pSession);
      end;
    end;
    

    ParseUrl is a function that splits a URL in "hostname / filename" and TStringArray is an array of strings. I still have to review the code tomorrow but it looks fine and in my sniffer I saw the post data and headers being sent.