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

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read