Delphi Download File with WinInet with UserName an

2019-06-01 09:34发布

There are numerous articles of how to download a file using WinInet (that's where I got the code from), but they all seem to be older and/or closed. Downloading without a username and password works fine, but if I protect the folder (Using VodaHost) with username and password I keep getting an authentication error when trying to download a file:

401 Unauthorized......

If I access through a web browser the username/password dialog pops up and I can get in fine. The folder protected is:

http://www.mywebsite.com/downloads

I have set Server to: www.mywebsite.com and url to http://www.mywebsite.com/downloads. The username and paswsord has been validated using a web browser.

I have also tried many permutations and am getting a bit frustrated. The 'only' thing I can think of is that it's because the server is not protected, but a folder on the server. The server cannot be protected because it is/will be publicly accessible. If you need any more info just let me know.

Anyone have any ideas?

function Download(Server, Url, User, Pass, FileName : string): boolean;
const
  BUFFERSIZE = 4096;

var
  hSession: HINTERNET;
  hService: HINTERNET;
  hHTTP: HINTERNET;
  lpBuffer: array[0..BufferSize + 1] of Byte;
  BufferLength: DWORD;
  dwBytesRead: DWORD;
  dwSizeOfRq, Reserved, dwByteToRead: DWORD;
  localFile: file;
  fsize: DWORD;

begin
  try
    try
      // Downloads file at URL bypassing cache
      Result := False;

      // Initialize the Win32 Internet functions
      hSession := InternetOpen(PChar('Empyrean'), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ;
      // See if the session handle is valid
      if hSession = nil then
        Exit;

      hHTTP := InternetConnect(hSession, PChar(Server), INTERNET_DEFAULT_HTTP_PORT, PChar(User), PChar(Pass), INTERNET_SERVICE_HTTP, 0, 0);
      if hHTTP = nil then
        Exit;

      // InternetOpenUrl opens a handle to the Internet file using a URL. The flags indicate that the file will always
      // be read from the Internet rather than the cache
      //hService := InternetOpenUrl(hSession, pChar(url), nil, 0, INTERNET_FLAG_DONT_CACHE or INTERNET_FLAG_PRAGMA_NOCACHE or INTERNET_FLAG_RELOAD, 0);
      hService := InternetOpenUrl(hSession, pChar(url), nil, 0, INTERNET_FLAG_RELOAD, 0);

      // See if the session handle is valid
      if hService = nil then
      begin
        InternetCloseHandle(hService);
        Exit;
      end;

      HttpQueryInfo(hService, HTTP_QUERY_STATUS_CODE or HTTP_QUERY_FLAG_NUMBER, @dwByteToRead, dwSizeOfRq, Reserved);
      AssignFile(localFile, FileName);
      {$I-}
        Rewrite(localFile, 1);
     {$I+}
     if IOResult <> 0 then
      begin
        ShowMessage('Cannot create local file: ' + FileName);
        InternetCloseHandle(hService);
        Exit;
      end;
      BufferLength := BUFFERSIZE;

      // These three variables will store the size of the file, the size of the HttpQueryInfo content, and the number of bytes read in
      // total. Now determine the length of a file in bytes
      dwByteToRead := 0;
      dwSizeOfRq := 4; // BufferLength
      Reserved := 0;

      // get the file's size.
      if not HttpQueryInfo(hService, HTTP_QUERY_CONTENT_LENGTH or HTTP_QUERY_FLAG_NUMBER, @dwByteToRead, dwSizeOfRq, Reserved) then
        dwByteToRead := 0;
      FSize := 0;
      BufferLength := BUFFERSIZE;

      while (BufferLength > 0) do
      begin
      // Read data from the hService handle
        if not InternetReadFile(hService, @lpBuffer, BUFFERSIZE, BufferLength) then
          Break;
        if (BufferLength > 0) and (BufferLength <= BUFFERSIZE) then
          BlockWrite(localFile, lpBuffer, BufferLength);
        fsize := fsize + BufferLength;

      // Check the size of the remaining data. If it is zero, break
        if BufferLength > 0 then
          Result := True;
      end;

      CloseFile(localFile);
      Result := True;
    except

    end;
  finally
    // Close the Internet handle that the application has opened
    InternetCloseHandle(hService);
    InternetCloseHandle(hSession);
    InternetCloseHandle(hHTTP);
  end;

end;

2条回答
你好瞎i
2楼-- · 2019-06-01 10:26

Thanks to all for the advice. I now have the code working by including the username/password in the URL:

Server := 'www.myServer.com';
URL := 'http://user:pSassword@www.myserver.com/downloads/filetodownload';
查看更多
放荡不羁爱自由
3楼-- · 2019-06-01 10:33

Use InternetSetOption() to specify INTERNET_OPTION_USERNAME and INTERNET_OPTION_PASSWORD values for the handle returned by InternetConnect(), before calling InternetOpenUrl().

Read the documentation for more details:

Handling Authentication

In particular:

The InternetOpenUrl and HttpSendRequest functions complete successfully even when authentication is required. The difference is, the data returned in the header files and InternetReadFile would receive an HTML page informing the user of the status code.

So if InternetOpenUrl() is "successful", you will have to use HttpQueryInfo() to get the status code, and if it is 401 then set a username/password (prompting the user if needed) and try the request again. There is an example of that in the above documentation. The response provides you with the actual file requested only if the status code is 200.

查看更多
登录 后发表回答