SAMPLE: PostMon.exe Demonstrates How to Use URL Moniker to POST Data (165800)



The information in this article applies to:

  • Microsoft Internet Explorer (Programming) 3.0
  • Microsoft Internet Explorer (Programming) 5
  • Microsoft Internet Explorer (Programming) 5.5

This article was previously published under Q165800

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. PostMon.exe is a sample a dialog-based application that demonstrates the modifications necessary to perform a POST.

MORE INFORMATION

The following file is available for download from the Microsoft Download Center:
For additional information about how to download Microsoft Support files, click the following article number to view the article in the Microsoft Knowledge Base:

119591 How to Obtain Microsoft Support Files from Online Services

Microsoft scanned this file for viruses. Microsoft used the most current virus-detection software that was available on the date that the file was posted. The file is stored on security-enhanced servers that help to prevent any unauthorized changes to the file. 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:
  1. 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;
    }
    					
  2. 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.
  3. 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:
  1. Copy POSTMON.ASP and REDIR.ASP to a directory on a Windows 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.
  2. Copy REDIR.HTM to the designated "Home Directory" by IIS, typically the \inetpub\wwwroot subdirectory. Verify that this directory has read permission.
  3. 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.
  1. Run POSTMON_\POSTMON.EXE.
  2. 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.
  3. The default method is POST as indicated by the radio button. Click submit, and observe the results.
  4. 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

Modification Type:MinorLast Reviewed:8/9/2004
Keywords:kbdownload kbfile kbinfo kbsample KB165800