MORE INFORMATION
Using the WebPost APIs
One method for uploading files is by using the WebPost APIs, with either
the HTTP POST method or the ActiveX upload control. The WebPost APIs are
fully documented and explained in Internet Client SDK.
The drawback is that both of these methods require that the server have a
special component that handles posted data and saves it in a file on the
server's file system. The exceptions are WebPost and ActiveX control
uploading when using an FTP posting provider. However, this requires
installing and configuring an FTP server in addition to the WWW server.
The Microsoft Posting Acceptor shipped with Windows NT 4.0 Option Pack
(NTOP) provides the back-end functionality for file uploads via the
methods described above. Please see the NTOP documentation and Microsoft
Posting Acceptor release notes (also shipped with NTOP) for information on
how to configure and use Posting Acceptor and File upload control.
By Using HTTP Protocol PUT Functionality
The HTTP protocol PUT functionality method does not require any components
on the server to handle upload data. The PUT functionality is built-in to
IIS 4.0. Please note that not all Internet Browsers can handle the HTTP
PUT verb. The following discussion applies to applications written with
the WinInet APIs, which give the programmer the ability to create and send
an HTTP request programmatically.
The PUT method is described in the HTTP/1.1 RFC 2068
(
http://www.w3.org/Protocols/rfc2068/rfc2068)
With this method the client supplies a URL and sends the data in the body of the request. The main
difference between POST and PUT is that with PUT, the URL is not the name
of a server application that will handle the client's data. Instead, the
URL is the name of the file that will be created by the server to store
the received data. If the URL already exists, then it will be overwritten
by the server. Please note that the virtual directory referred to in the
URL must have WRITE permission set (for IIS 4.0, this is configurable via
Directory Properties in MMC).
For example, the following HTTP request (only verb and URL is shown)
creates Page.htm file in the /test virtual directory. File will contain
data sent with the request:
PUT /Test/Page.htm
Because WinInet APIs enable the programmer to create any valid HTTP
request, they can be easily used to upload data to the server. The
following steps need to take place:
- A Request must be opened with the verb PUT.
- The object of the request may not be NULL and should be a valid URL on
the server (although the file does not need to exist at the time of the
request).
- The newly created URL will contain data supplied with the request.
Following is a snippet of the sample code that can be used:
...
hReq = HttpOpenRequest (hConnect, "PUT", "/test/page.htm", ...)
CHAR szContent [] = "Hello, World!"
HttpSendRequest (hReq, NULL, 0, szContent, lstrlen (szContent))
...
Upon running this code, IIS 4.0 will create the file Page.htm in virtual
directory /test. The file will contain the "Hello, World!" string.
Please note that HttpSendRequest can be used only with a single buffer of
limited size. HttpSendRequestEx and InternetWriteFile can be used to send
buffers of any size as follows:
BOOL UseHttpSendReqEx(HINTERNET hConnect, TCHAR *upFile)
{
INTERNET_BUFFERS BufferIn = {0};
DWORD dwBytesRead;
DWORD dwBytesWritten;
BYTE pBuffer[1024]; // Read from file in 1K chunks
BOOL bRead, bRet;
BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS );
HINTERNET hRequest = HttpOpenRequest (hConnect, "PUT",
"/test/page.htm", NULL, NULL, NULL, 0, 0);
if (!hRequest)
{
printf("Failed to open request handle: %lu\n", GetLastError ());
return FALSE;
}
HANDLE hFile = CreateFile (upFile, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("\nFailed to open local file %s.", upFile);
return FALSE;
}
BufferIn.dwBufferTotal = GetFileSize (hFile, NULL);
printf ("File size is %d\n", BufferIn.dwBufferTotal );
if(!HttpSendRequestEx( hRequest, &BufferIn, NULL, HSR_INITIATE, 0))
{
printf( "Error on HttpSendRequestEx %lu\n",GetLastError() );
return FALSE;
}
DWORD sum = 0;
do
{
if (!(bRead = ReadFile (hFile, pBuffer, sizeof(pBuffer),
&dwBytesRead, NULL)))
{
printf ("\nReadFile failed on buffer %lu.",GetLastError());
break;
}
if (!(bRet=InternetWriteFile( hRequest, pBuffer, dwBytesRead,
&dwBytesWritten)))
{
printf ("\nInternetWriteFile failed %lu", GetLastError());
break;
}
sum += dwBytesWritten;
}
while (dwBytesRead == sizeof(pBuffer)) ;
CloseHandle (hFile);
printf ("Actual written bytes: %d\n", sum);
if(!HttpEndRequest(hRequest, NULL, 0, 0))
{
printf( "Error on HttpEndRequest %lu \n", GetLastError());
return FALSE;
}
return TRUE;
}
NOTE: IIS may lock a file immediately after it processes the GET request.
Therefore, in the following sequence of requests, the second PUT may fail:
PUT /page.test
GET /page.test
PUT /page.test
Even though the failure is caused by locking violation, IIS may report it
as error caused by ACL on the resource (error 401.3). To prevent this
problem, the following methods can be used: