Search
Recommended for You

Creating an iPhone-based Web Service: Part 2


The iPhone's "no disk access" policy shouldn't bar you from sharing your application's files with the world at large. Last week, I showed you how to build a listening socket that polled for requests on a random port. This week, it's time to parse those requests.

In the code I showed last week, every time the accept function receives a connection, it calls the handleWebRequest: method, passing the socket information as its argument. It's the method's role to read that data, parse it and respond in some fashion.

To retrieve the data, just read it into a buffer and mark the end with a terminating null:

    int len = read(fd, buffer, BUFSIZE);     
    buffer[len] = '\0';

Simple HTML file requests look something like GET /FILE HTTP/1.1. By skipping 4 characters and stopping at the HTTP, you've got the name of the file being requested. Here, I convert the C-string to NSString and then extract the request components:

    NSString *request = [NSString stringWithCString:buffer];
    NSArray *reqs = [request componentsSeparatedByString:@"\n"];
    NSString *getreq = [[reqs objectAtIndex:0] substringFromIndex:4];
    NSRange range = [getreq rangeOfString:@"HTTP/"];
    if (range.location == NSNotFound)
    {
        printf("Error: GET request was improperly formed\n");
        close(fd);
        return;
    }

To keep your web server simple, you need to do just three things with this request. First, if the request is for /, create a custom index.html file populated with the names of the files on offer. Second, if the request is for a file name, return a properly formatted result with that data. Finally, if neither of those conditions are met, return an error.

Just those three things provide all the functionality you need to interact with any standard web browser, including Safari, Firefox, Explorer, and so forth.

This week, I'll show you how to do the first of those three things. The following snippet builds an index.html file from the contents of the iPhone's onboard camera roll and snazzes it up with a little custom CSS.

- (NSString *) createindex
{
    // Return a custom Index.html populated with camera roll images
    NSArray *array = [[[NSFileManager defaultManager] directoryContentsAtPath:PICS_FOLDER]
                      pathsMatchingExtensions:[NSArray arrayWithObject:@"JPG"]];
    char baseHostName[255];
    gethostname(baseHostName, 255);
    NSString *hostname = [NSString stringWithCString:baseHostName];
    
    NSMutableString *outdata = [[NSMutableString alloc] init];
    [outdata appendString:@"<

style>html {background-color:#eeeeee} body { background-color:#FFFFFF; font-family:Tahoma,Arial,Helvetica,sans-serif; font-size:18x; margin-left:15%; margin-right:15%; border:3px groove #006600; padding:15px; } </style>"]; [outdata appendFormat:@"<h1>Pictures from %@</h1>", hostname]; [outdata appendString:@"<bq>The following images are hosted live from the iPhone's DCIM folder.</bq"]; [outdata appendString:@"<p>"];

for (NSString *fname in array)
{
NSDictionary *picDict = [[NSFileManager defaultManager] fileAttributesAtPath:[PICS_FOLDER stringByAppendingPathComponent:fname] traverseLink:NO];
NSString *modDate = [[[picDict objectForKey:NSFileModificationDate] dateWithCalendarFormat:@"%Y-%m-%d at %H:%M:%S" timeZone:nil] description];
[outdata appendFormat:@"* <a href=\"%@\">%@</a> [%8d bytes, %@]<br />\n", fname, fname, [picDict objectForKey:NSFileSize], modDate];
}
[outdata appendString:@"</p>"];
[array release];

return [outdata autorelease];
}


Next week, I'll show you how to serve the actual files and to respond to errors.

AddThis Social Bookmark Button
Comments (3)

3 Comments

great work so far, im getting a lot from this!

cheers, rob

Paul Gleeson said:

Where is the PICS_FOLDER defined?
Am I missing something obvious?
Could be as I am a beginner
Thanks, Paul

David M said:

Thanks, great information like always. Keep it up!

Quality reviews and articles

Leave a comment


Type the characters you see in the picture above.