|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Fig. Graphs of uploading time needed in ASP/ISAPI. DescriptionThis article describes two ways of uploading images and files to your web server, and the advantages and disadvantages of both. My contribution is based on the comparison between the different methods. I didn't invent any Microsoft upload technique :). This article is based on an ASP technique which I got from my colleague Doru Paraschiv and on a very good article from MSDN. My special thanks to Panos Kougiouris, for his help in revealing the ISAPI binary streaming techniques. Check out Creating a DLL to Enable HTTP-based File Uploads with IIS. Uploading files from a browser is often a web site requirement. For instance, let's say that you have created a web site for a real estate company. The site contains listings of properties along with a picture of each property. Realtors can add new listings through an administration section of the site. Adding text for the new listing is easy using an HTML form. Then one day a realtor tells you that she wants to upload a photo of a property for sale in your site. How would you do that with ASP and ISAPI? How to useBoth the methods use the same functional structure. First, the user must complete the fields in the PostFile.asp form. The JavaScript function
Fig. Image of the uploading form. Second, the user must receive the results of Upload.asp (in case of ASP) or UploadExt.dll (in case of ISAPI) in the ReceiveRedirect.asp file. It is also possible to finish the execution in Upload.asp or UploadExt.dll but in most cases a redirect is needed to catch all the parameters of the form to write the file on another server. The ISAPI form uses two optional hidden parameters to tell the DLL the directory to store the upload (if isn't specified the script uses c:\temp\) and the name of the ASP redirection page (if the user wants this). The default value of the upload directory (the default is relative to root site directory \Data\) is put in the form
Fig. Image of the receiving ASP page. Your IIS anonymous user account, usually ASP upload details
Upload the fileThe first requirement for this process is to have an HTML form that actually uploads (or "posts") a file to your ASP page. The ASP script that saves the file starts out by allowing the server a generous amount of time to process whatever file is uploaded to it. This is a very important consideration, because it can take a long time to process a large file. If your script times out before the process finishes, the uploaded file will be lost! Next, the script sets up some needed constants and defines several functions. We'll return to these functions in a moment, but for now, let's move on to the main part of the script and see how this process really works. Catch the POSTThe first thing the script does is retrieve all the data that was posted from the HTML file and place it into a variable called You have to transform all that binary data into something more friendlier. This is done with a simple loop that marches through the extracted binary data and, using a series of calls to some binary data manipulation functions, converts the data into an easily readable format and places it into the variable Breaking up the raw dataOnce we have the posted data in ASCII form, it's a fairly simple process to work through it and extract each form field from it. The first step is to determine if our data is properly encoded. After that, we can determine the boundary between each form element. Amazingly, both these pieces of information can be found in one convenient place: the -----------------------------7d22151d40264
Given this simple structure, it's easy to extract the information we need. First, we use the Each chunk of form data is itself in two chunks. The first is an informational chunk that tells all about the form field (i.e., its name and any associated information). The second chunk is the actual form data that was transmitted. Content-Disposition: form-data; name="RedirectPage"
ReceiveRedirect.asp
-----------------------------7d22151d40264
Content-Disposition: form-data; name="Name"
Adrian Bacaianu
-----------------------------7d22151d40264
Content-Disposition: form-data; name="Upload"
Submit Query
-----------------------------7d22151d40264--
As you can see in this listing, the boundary information is used to separate each form field and its data. Unfortunately, the informational chunk of a form field isn't separated from the data chunk by anything obvious. Well, actually, it is obvious, but we've all grown so used to ignoring this particular separator that it's hard to notice. Basically, two pairs of carriage return and line feed characters separate the information chunk and the data chunk. That's a total of four bytes between the chunks. Splitting apart the form dataNow, it would be great if we could extract all of this form data into a nice collection, just like the At this point, it's a simple matter of looping through all of the form fields that were extracted when After these chunks are extracted, the informational chunk is examined (via the If the field isn't a file, its name is extracted using the That's it! Once the loop finishes, the Saving the fileAt this point, all that's left is to actually save the uploaded file (or files) on the server. Note that the contents of the other form fields are employed (via the ConclusionWell, that wasn't really too hard, was it? Of course, there are some drawbacks to this approach: Large files take a long time to process and binary files can be difficult to handle properly. But, once you've got the basics down (and now you do!) it's a fairly straightforward process to adapt this technique to handle more troublesome files. And, best of all, you don't have to buy and install a third-party object or use the much maligned posting acceptor! ISAPI upload detailsIn MSDN, Panos has explained this very well:
On the server side though, ASP does not have a way to access data in the multipart/form-data format. There is a posting acceptor component, but its programmability is limited and it always stores the uploaded files into the file system. For instance, if you know in advance that the users must always load small files and you process these files in memory, you might want a more flexible solution. The most flexible way to access the uploaded file is through a C++ ISAPI extension DLL. The When a browser sends a request to a server, it always sends an HTTP packet with the data describing the request. The packet always contains the virtual path of the URL. For instance, if you call http://myserver/default.asp, the packet will contain the /default.asp path. In addition, if the request is the result of submitting an HTML form, the request will contain the contents of the The next question, of course, is concerned with how the data is encoded. It turns out that it's done using MIME encoding. The default (and the simplest) encoding is application/x-www-form-urlencoded, which is described in HTML 4.01 specification in W3C. The application/xwww-form-urlencode type is simple and perfect for submitting a few text fields. For large text files or images, the specification defines another encoding: multipart/form-data. The following snippet shows what the HTTP packet of a form submitted using the multipart/form-data encoding looks like. Raw data posted to the web server is in following format: -----------------------------7d22151d40264
Content-Disposition: form-data; name="Filename"
UploadFileName.txt
-----------------------------7d22151d40264
Content-Disposition: form-data; name="Filedata";
filename="C:\boot.ini"
Content-Type: application/octet-stream
"The ISAPI extension DLL parses the input stream and collects all the name/value pairs. Then it creates a new dictionary COM object and stores the name/value pairs in the dictionary. Finally, it generates a new ID and stores the new dictionary into the dictionary of dictionaries using that ID as the key". To access a parameter from that collection is very simple: //here create the "PathData" param MultipartEntry *pEntry = cParser["PathData"]; if(pEntry != NULL) sPath = pEntry->Data(); //here get data of //the "PathData" param sName = cParser[2]->Name(); //here get the name //("PathData") of the 2 param If the response is printed to a web browser directly from an ISAPI extension, we use the void SendToBrowser(LPEXTENSION_CONTROL_BLOCK pECB, const String & sMsg) { DWORD dwLen = sMsg.size(); if(dwLen > 0) //use HTTP WriteClient function pECB->WriteClient(pECB->ConnID, (LPVOID) sMsg.c_str(), &dwLen, 0); } If the response is redirected from the ISAPI extension to another ASP page, we use the void RedirectBrowser(LPEXTENSION_CONTROL_BLOCK pECB, const String & sMsg) { DWORD dwLen = sMsg.size(); if(dwLen > 0) // use HTTP ServerSupportFunction function pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_URL, (LPVOID)sMsg.c_str(), &dwLen, 0); } ConclusionThis article describes two ways of uploading images and files to your web server, and the advantages and disadvantages of both. There are also other ways to do the upload, which will be presented in another article!
|
||||||||||||||||||||||