Developer --> Technical Publications

     


A Case Study: Downloading Data From a URL

This section describes how the sample application SamplePost posts information to an HTTP URL and download the URL's response using the URL Access Manager function URLDownload .

Listing 2-2 shows the header file for the application, SamplePost.h , which contains definitions of the URL from which data is to be downloaded ( kSampleURL ) and the structure urlDownInfo , as well as declarations of the function DoSamplePost , which calls URLDownload , and a system event callback function, MyURLCallbackProc , which is a place holder for code that handles system events that occur during the download.

SamplePost.h
#define kSampleURL "http://www.internic.net/cgi-bin/itts/whois" typedef struct urlDownInfo *URLDownInfoPtr; typedef struct urlDownInfo { URLReference urlRef; FSSpec * destination; Handle destinationHandle; URLOpenFlags openFlags; URLSystemEventProcPtr eventProc; void * userContext; Boolean done; OSStatus errorCode; } URLDownloadInfo; static void DoSamplePost (); pascal OSStatus MyURLCallbackProc( void*, EventRecord * );

SamplePost is a multi-threaded application. As a result, in Listing 2-3, SamplePost's main function calls the Memory Manager functions MaxApplZone and MoreMasters in its main function. Note that all URL Access Manager functions are threaded with Thread Manager cooperative threads. These threads are nonreentrant on PowerPC.

SamplePost's main function
#include <stdio.h> #include <Events.h> #include <Threads.h> #include <Processes.h> #include <Files.h> #include "URLAccess.h" #include "SamplePost.h" int main (void){ OSStatus err = noErr; // Call MaxAppleZone() when using the Thread Manager. MaxApplZone(); for (i = 0; i < 20; i++) { MoreMasters(); }

Listing 2-4 shows SamplePost calling the function URLAccessAvailable to verify that the URL Access Manager is available. If the URL Access Manager is available, DoSamplePost is called.

Listing 2-4 Verifying the availability of the URL Access Manager
// Make sure the URL Access Manager is available. if ( URLAccessAvailable()) { DoSamplePost(); } else { // Call error handling function. }

In Listing 2-5, DoSamplePost defines a URLDownloadInfo structure named myRef that is uses to store information for calling URLDownload . The DoSamplePost function then calls NewHandle to allocate the memory in which the downloaded information will be stored, creates a URL reference, and stores it in myRef.urlRef .

Allocating memory and creating a URL reference
static void DoSamplePost ( void){ OSStatus err = noErr; ThreadID threadID = 0; URLDownloadInfo myRef; Handle downloadHandle = NULL; long downloadSize = 0; printf( "<·>DoSamplePost() Enter\n"); downloadHandle = NewHandle(0); if ( downloadHandle == NULL) { // Call error handling function. } // Create a URLReference err = URLNewReference( kSampleURL, &myRef.urlRef ); if ( err != noErr) { // Call error handling function. }

As shown in Listing 2-6, DoSamplePost calls the function URLSetProperty to set the HTTP request method property value to the 4-byte string "POST" and the value of the HTTP request body property value to the 19-byte string "whois_nic=apple.com" . When you set the property identified by kURLHTTPRequestBody , the URL Access Manager automatically adds the length of the value identifed by kURLHTTPRequestHeader to the request, so you do not need to set the request header explicitly.

Setting URL properties
URLSetProperty (myRef.urlRef, kURLHTTPRequestMethod, "POST", 4); URLSetProperty (myRef.urlRef, kURLHTTPRequestBody, "whois_nic=apple.com", 19);

Next, DoSamplePost uses the remaining fields of the myRef structure to store values that will be used as parameters for calling URLDownload .

  • DoSamplePost sets myRef.destination to NULL . When NULL is provided as the destination parameter to the URLDownload , the calling application indicates that the downloaded data is not going to be written to a file on disk.
  • DoSamplePost sets myRef.destinationHandle to the value of downloadHandle , which is the location in memory at which the downloaded data is to be stored.
  • DoSamplePost sets myRef.OpenFlags to kURLDisplayProgressFlag . When the value of the openFlags parameter to URLDownload is kURLDisplayProgressFlag , URLDownload displays a progress indicator during the download process. You may wish to provide a system event callback function to handle system events that occur.
  • DoSamplePost sets myRef.eventProc to the address of the SamplePost application's system event callback function. When DoSamplePost calls URLDownload, it will specify myRef.eventProc as the eventProc parameter. If a system event occurs while the progress indicator is displayed, the URL Access Manager will call the function specified by the eventProc parameter and will pass to it the value of the userContext parameter, which is described next.
  • DoSamplePost sets myRef.userContext to point to myref . When DoSamplePost calls URLDownload , it will specify myRef.userContext as the userContext parameter. Your application can use the user context to set up its context when the system event callback function is called.
  • Listing 2-7 illustrates setting these values.

    Setting the URLDownload parameters
    myRef.destination = NULL; myRef.destinationHandle = downloadHandle; myRef.openFlags = kURLDisplayProgressFlag; myRef.eventProc = &MyURLCallbackProc; myRef.userContext = &myRef; myRef.errorCode = 0;

    Once the URL reference has been created, its properties set, and the parameters for URLDownload prepared, DoSamplePost is ready to call URLDownload , as shown in Listing 2-8. If the download is successful, DoSamplePost calls the function URLGetProperty to obtain the size of the downloaded data using the downloadSize parameter.

    Listing 2-8 Calling the URLDownload function
    err = URLDownload( myRef.urlRef,myRef.destination,myRef.destinationHandle, myRef.openFlags, myRef.eventProc, myRef.userContext); myRef.errorCode = err; if ( myRef.errorCode != noErr) { // Call error handling function. } else { // Successful download. Get the size of the downloaded data. err = URLGetProperty(myRef.urlRef, kURLResourceSize, &downloadSize, 4); if ( err != noErr) { // Call error handling function. }

    In Listing 2-9 DoSamplePost calls SetHandleSize to set the size of downloadHandle to downloadSize + 1 and sets the value of the last byte of downloaded data to NULL . DoSamplePost calls printf to display the data, and concludes by disposing of the URL reference.

    Listing 2-9 Displaying the downloaded data
    downloadSize = GetHandleSize(downloadHandle); SetHandleSize(downloadHandle, (downloadSize+1)); (*myRef.destinationHandle)[downloadSize] = NULL; printf( "<·>==================== Downloaded Data ==================\n" ); printf( "%s", *myRef.destinationHandle ); DisposeHandle(downloadHandle); URLDisposeReference(myref.urlRef);

    Listing 2-10 shows a placeholder for SamplePost's system event callback function. The userContext parameter can be used to associate any particular call of URLDownload with any particular call of the system event callback function.

    Listing 2-10 SamplePost's system event callback function
    pascal OSStatus MyURLCallbackProc ( void *userContext, EventRecord *event ) { printf( "<·>System callback thread fired! Thread: %u\n", userContext ); return 0; }

    © 2000 Apple Computer, Inc. (Last Updated 20 July 2000)