File Uploading With ISAPI

Environment: ISAPI

Introduction

In this article, I will give you an easy way to upload files and work with forms using ISAPI. Uploading files with ISAPI can be useful even for ASP developers. ASP uploading is more complex and slower than ISAPI. For files over 100 Kb, ISAPI is significantly faster. I will provide you with three MFC-free classes—CQueryString, CWebForm, and CMultipartForm—for working with HTML Forms. These classes provide a fast a simple way to access any form's data. But first, let's start with the basics...

Query Strings

There are three ways that you can pass data from an HTML form your ISAPI Application, the simplest of them being in the query string. The query string is appended to the URL, with a question mark after the page name. Variables are given values using =, and appended using &; for example, isapi.dll?querystring=something&var=10. The query string is the simplest to work with; it requires only basic parsing to extract the important parts. The query string will always be available to the user, which can be good and bad. It allows the user to copy the URL, but also allows the user to view potentially sensitive data. You can pass data in a query string from a URL, or a form, which makes it very flexible. Any page can use both get and post data. To create a form that passes its data in the query string, you will need to set the method to get.

For example,

<form action=isapi.dll method=get>

POST Data

The second type of form is one that posts data. The post data string is identical to the query string, but it is hidden from the user. If it is sent through a secure connection, it cannot be viewed by anyone. To set up a form that posts data, you must set the method to post.

For example,

<form action=isapi.dll method=post>

Multipart Forms

As you can imagine, it would be difficult to send a file through a query string. There is a third type of form, called a multipart form, that splits each form field up into separate parts, allowing you to send both text and files. The data the server receives from a multipart form is shown below:

-----------------------------7d22a54d00264
Content-Disposition: form-data; name="file";
                     filename="C:\something.txt"
Content-Type: application/octet-stream

the data in the file.
this could be text or binary
-----------------------------7d22a54d00264
Content-Disposition: form-data; name="Some Field"

The value of some field
-----------------------------7d22a54d00264--

As you can see, this will require a bit different parsing. The header line will be different each time. To create a multipart form, you must set the enctype to multipart/formdata, as shown below.

For example,

<form action=isapi.dll method=post enctype="multipart/form-data">

Retrieving the Form Data

IIS will give you the first 48 Kb of post data, but the rest of the data you must read from the client yourself. This is done by using the ReadClient function, which is pointed to by the ECB. Internally, I store this data in the CDataBuffer class.

Structure

CQueryString provides the base class for CWebForm and CMultipartForm. It provides the query string parsing used by itself and CWebForm. It stores all the form data in a string to a string map. The data can be accessed using the [] operator or the GetValueD, GetValueI, and GetValueL methods. These methods differ only in their return values.

For example,

std::string str = QueryString["fieldname"]; 
double d = QueryString.GetValueD("fieldname");

CQueryString also provides an IsEmpty() method to determine whether a query string was passed or whether the form was posted. CWebForm adds the ability to read the post data from the client, which is handled by the internal function ReadFormData(). CWebForm uses CQueryString's parsing method. CMultipartForm is derived from CWebForm. It uses CWebForm's ReadFormData() method, but provides its own parse method along with storage for files. The file data is contained in the CFile class.

CFile allows you to get basic information about the file, as well as save the file or retrieve a copy of the file's data. Usage of these classes is simple; all you need to do is construct the class passing it your ECB and call its parse method. The only thing you need to be careful of is that you cannot construct a CWebForm and CMultipartForm object because the second one will not be able to read data from the client. Of course, there is no reason you would ever need to.

Usage

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
  CQueryString QueryString( pECB );
  QueryString.Parse();

  std::string name = QueryString["name"];
  std::string email = QueryString["email"];
  int age = QueryString.GetValueI("age");
}

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
  CWebForm Form( pECB );
  Form.Parse();

  std::string name = Form["name"];
  std::string email = Form["email"];
  int age = Form.GetValueI("age");
}

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
  CMultipartForm Form( pECB );
  CFile File1;
  CFile File2;
  Form.Parse();

  std::string name = Form["name"];
  std::string email = Form["email"];
  int age = Form.GetValueI("age");

  /// get the first file; we should check the name using
  /// GetFieldName to make sure it is the one we think it is
  if( Form.GetFirstFile( &File1 ) )
    File1.Save( "C:\\Uploads\\" + File1.GetClientFilename() );

  if( Form.GetNextFile( &File2 ) )
  {
    BYTE pData = new BYTE[File2.GetBufferSize()];
    File2.GetBuffer( pData );
    // do something with pData
    delete[] pData;
  }
}

That's all there is to it!

Compatibility

This application was written using the standard C++ library, so it should be Unix compatible. In fact, the sample application does not even include windows.h. However, I have only tested the application under Windows 2000 SP3 Pro and Server.

Setup

For IIS, you will need to give everyone write permissions in NTFS to the folder you are trying to save to. Do not give users write permission to your Web site or virtual directory! Make sure that write is unchecked in the virtual directory setup. The virtual directory will need execute scripts and executables permissions. To run the sample, place the .dll and demo.html in the same directory and browse to demo.html.

Downloads

Download demo project - 111 Kb
Download source - 10 Kb


Comments

  • doesnt' work well on firefox

    Posted by gospaservice on 01/04/2012 05:37am

    It doesnt' work well on firefox: the file is uploaded, but the page of result ("you wrote:..." etc) is not displayed. How to fix it? (On Internet Explorer and Chrome it works well). Thank you so much!

    Reply
  • Bug: multiple files + fix

    Posted by Legacy on 01/01/2004 12:00am

    Originally posted by: Mordred

    There's a bug in Parse() function of the CMultiPartForm class that always gets one byte less of
    
    the file, thus preventing you from getting more than one file.

    To fix it simply change:

    /// allocate buffer
    int nDataLen = dataend - startpos;

    to:
    int nDataLen = dataend - startpos;
    if(bFile) // we need to one byte more for strings, but not with files
    nDataLen++;


    Cheers, great classes btw! :)


    Reply
  • how to use CWebForm CMultipartForm in a mfc isapi ?

    Posted by Legacy on 03/25/2003 12:00am

    Originally posted by: iwaitu

    how to define ON_PARSE_COMMAND.

    can you give me a example ?

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Protecting business operations means shifting the priorities around availability from disaster recovery to business continuity. Enterprises are shifting their focus from recovery from a disaster to preventing the disaster in the first place. With this change in mindset, disaster recovery is no longer the first line of defense; the organizations with a smarter business continuity practice are less impacted when disasters strike. This SmartSelect will provide insight to help guide your enterprise toward better …

  • Live Event Date: July 30, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT You may already know about some of the benefits of Bluemix, IBM's open platform for developing and deploying mobile and web applications. Check out this upcoming eSeminar that focuses on building an Android application using the MobileData service, with a walk-through of the real process and workflow used to build and link the MobileData service within your application. Join IBM's subject matter experts as they show you the way to build a base …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds