The information in this article applies to:
- Microsoft ActiveX SDK, version 1.0
SUMMARY
Depending on the quantity of data to be transmitted in a request to an HTTP
server, it may be desirable, or even necessary, to use the POST method as
opposed to the GET method, which is limited to sending approximately 2K of
data to the server. This article explains the requirements for using URL
Monikers to POST data to an HTTP server. Sample code in the form of a
dialog-based application is also provided.
The following file is available for download from the Microsoft Software
Library:
~ Postmon.exe (size: 42091 bytes)
For more information about downloading files from the Microsoft Software
Library, please see the following article in the Microsoft Knowledge Base:
ARTICLE-ID: Q119591
TITLE : How to Obtain Microsoft Support Files from Online Services
MORE INFORMATION
The PROGRESS sample included with the ActiveX SDK for Internet Explorer 3.x
and the Internet Client SDK for Internet Explorer 4.0 demonstrated how to
perform the GET method using a URL Moniker. Building upon that knowledge,
the POSTMON sample demonstrates the modifications necessary to perform a
POST.
Following is a description of the major implementation details that need to
be accounted for when performing a POST using a URL Moniker:
- In the implementation of IBindStatusCallback::GetBindInfo, specify the
action BINDVERB_POST as well as the data to be posted in a pointer to
the BINDINFO structure provided by the URL Moniker. At this time,
HGLOBAL is the only supported format for the data to be transmitted to
the server. Take special caution when posting large quantities of data
by checking the return values of memory allocation functions. If memory
is limited, these functions may fail. Also observe that the sample
implementation fills in the pUnkForRelease member of the STGMEDIUM data
structure. This allows the client to manage the data through the
reference count on the object that implements IBindStatusCallback. In
this case, the client should free the data only on final release of the
object that implements the callback interface:
STDMETHODIMP
CBindStatusCallback::GetBindInfo(DWORD* pgrfBINDF,
BINDINFO* pbindInfo)
{
if (m_fRedirect && BINDVERB_POST == m_dwAction)
{
// You are being redirected by the server.
// The method is changed to GET here so no data is posted below
SetStatusText(_T("Switching method to GET"));
m_dwAction = BINDVERB_GET;
}
*pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE
| BINDF_PULLDATA;
*pgrfBINDF |= BINDF_GETNEWESTVERSION
| BINDF_NOWRITECACHE;
// Set up the BINDINFO data structure
pbindInfo->cbSize = sizeof(BINDINFO);
pbindInfo->dwBindVerb = m_dwAction; // here's where the action is
pbindInfo->szExtraInfo = NULL;
// Initialize the STGMEDIUM.
memset(&pbindInfo->stgmedData, 0, sizeof(STGMEDIUM));
pbindInfo->grfBindInfoF = 0;
pbindInfo->szCustomVerb = NULL;
// set up action-specific members
switch(m_dwAction)
{
case BINDVERB_POST:
// only POST data when the method is POST
if (m_hDataToPost)
{
// Fill the STGMEDIUM with the data to post
// this is the only medium urlmon supports right now
pbindInfo->stgmedData.tymed = TYMED_HGLOBAL;
pbindInfo->stgmedData.hGlobal = m_hDataToPost;
pbindInfo->stgmedData.pUnkForRelease =
(LPUNKNOWN)(LPBINDSTATUSCALLBACK)this; // maintain control
AddRef(); // It will be freed on final release
// the following must be exact! GlobalSize() rounds up.
pbindInfo->cbstgmedData = m_cbDataToPost;
}
break;
case BINDVERB_GET:
break;
default:
return E_FAIL;
}
- In the case of a redirect response from the server, a URL Moniker
notifies the client of a redirect request through a call to
IBindStatusCallback::OnProgress with a status code of
BINDSTATUS_REDIRECTING. In this case, the client should stop posting
data regardless of whether the new URL would accept it. The client
should detect this status code in their implementation and set a
flag in their callback implementation and modify the behavior of
GetBindInfo appropriately as shown above in the m_fRedirect case. For
more information on redirection, see RFC 1945 referenced below.
RFC 2068 referenced below contains a note that states the following:
“When automatically redirecting a POST request after receiving a 301
status code, some existing HTTP/1.0 user agents will erroneously change
it into a GET request.”
For compatibility with Netscape Navigator, the URL moniker performs such
an action.
- The client object that implements IBindStatusCallback should also
implement IHttpNegotiate. The following is a basic implementation of
this method defined in this interface. Observe that when the transaction
begins, in order to POST data the client must specify the
additional header "Content-Type: application/x-www-form-urlencoded."
This header indicates that the data being posted is URL-encoded form
data. If a different Content-Type is being posted to the server, the
data must be encoded according to that content-type's rules and the
appropriate content type header specified via
IHttpNegotiate::BeginningTransaction:
STDMETHODIMP
CBindStatusCallback::BeginningTransaction(LPCWSTR szURL,
LPCWSTR szHeaders,
DWORD dwReserved,
LPWSTR __RPC_FAR *pszAdditionalHeaders)
{
// Here's our opportunity to add headers
if (!pszAdditionalHeaders)
{
return E_POINTER;
}
*pszAdditionalHeaders = NULL;
// This header is required when performing a POST operation
if (BINDVERB_POST == m_dwAction && m_hDataToPost)
{
const WCHAR c_wszHeaders[] =
L"Content-Type: application/x-www-form-urlencoded\r\n";
LPWSTR wszAdditionalHeaders =
(LPWSTR)CoTaskMemAlloc(
(wcslen(c_wszHeaders)+1) *sizeof(WCHAR));
if (!wszAdditionalHeaders)
{
return E_OUTOFMEMORY;
}
wcscpy(wszAdditionalHeaders, c_wszHeaders);
*pszAdditionalHeaders = wszAdditionalHeaders;
}
return NOERROR;
}
STDMETHODIMP CBindStatusCallback::OnResponse(DWORD dwResponseCode,
LPCWSTR szResponseHeaders,
LPCWSTR szRequestHeaders,
LPWSTR __RPC_FAR *pszAdditionalRequestHeaders)
{
if (!pszAdditionalRequestHeaders)
{
return E_POINTER;
}
*pszAdditionalRequestHeaders = NULL;
return NOERROR;
}
See the instructions below on obtaining the sample. To build the sample,
refer to the README.TXT file included in the self-extracting archive. The
file POSTMON.CPP contains some explanation of the sample's interface.
To use the sample, perform the following steps:
- Copy POSTMON.ASP and REDIR.ASP to a directory on an NT 4.0 server
running Internet Information Server (IIS) version 3.0. The directory
should be recognized by IIS as a virtual root with execute permission.
- Copy REDIR.HTM to the designated "Home Directory" by IIS, typically the
\inetpub\wwwroot subdirectory. Verify that this directory has read
permission.
- Build the POSTMON sample from the command line using NMAKE as described
in the README.TXT file. NMAKE will create POSTMON.EXE on the designated
output directory (in this case, POSTMON_ has been specified as the
output directory).
NOTE: This NMAKE-generated POSTMON.EXE should not be confused with the
downloadable, self-extracting archive of this sample of the same name.
- Run POSTMON_\POSTMON.EXE.
- Modify the POSTMON address textbox to specify a valid path to
POSTMON.ASP. Note that you must not specify a local file path because a
POST or a GET will only succeed if the client interacts with an HTTP
server.
- The default method is POST as indicated by the radio button. Click
submit, and observe the results.
- To test redirection, modify the POSTMON address textbox to specify a
valid URL to REDIR.ASP, click submit and observe the results. The
contents of REDIR.HTM will be displayed.
REFERENCES
Berners-Lee, T. RFC 1945, "The Hypertext Transfer Protocol -- HTTP/1.0"
Fielding, R. RFC 2068, "Hypertext Transfer Protocol -- HTTP/1.1"
Asynchronous Moniker Specification included with the ActiveX SDK
Keywords : AXSDKUrlMon kbsample kbfile
Version : 1.0
Platform : WINDOWS
Issue type : kbinfo
Solution Type : kbfile
|