diff --git a/ChangeLog b/ChangeLog index e692277..cb6d4c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-05-09 Richard Frith-Macdonald + + * WebServer.[hm]: Add method to encode a form from a dictionary + into a data object ... convenience for where form data is needed. + 2005-03-02 Richard Frith-Macdonald * WebServer.[hm]: Add support for basic http authentication either diff --git a/WebServer.h b/WebServer.h index 83ea16b..619d692 100644 --- a/WebServer.h +++ b/WebServer.h @@ -266,6 +266,20 @@ - (unsigned) decodeURLEncodedForm: (NSData*)data into: (NSMutableDictionary*)dict; +/** + * Encode an application/x-www-form-urlencoded form and store its + * representation in the supplied data object.
+ * The dictionary contains the form, with keys as data objects or strings, + * and values as arrays of values to be placed in the data. + * Each value in the array may be a data object or a string.
+ * As a special case, a value may be a data object or a string rather + * than an array ... this is treated like an array of one value.
+ * All non data keys and values are convertd to data using utf-8 encoding.
+ * This method returns the number of values actually encoded. + */ +- (unsigned) encodeURLEncodedForm: (NSDictionary*)dict + into: (NSMutableData*)data; + /** * Returns YES if the server is for HTTPS (encrypted connections), * NO otherwise. diff --git a/WebServer.m b/WebServer.m index 090bf45..44787ad 100644 --- a/WebServer.m +++ b/WebServer.m @@ -481,6 +481,130 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf) return fields; } +static NSMutableData* +escapeData(const unsigned char* bytes, unsigned length, NSMutableData *d) +{ + unsigned char *dst = (unsigned char*)[d mutableBytes]; + unsigned int spos = 0; + unsigned int dpos = [d length]; + + [d setLength: dpos + 3 * length]; + while (spos < length) + { + unsigned char c = bytes[spos++]; + unsigned int hi; + unsigned int lo; + + switch (c) + { + case ',': + case ';': + case '"': + case '\'': + case '&': + case '=': + case '(': + case ')': + case '<': + case '>': + case '?': + case '#': + case '{': + case '}': + case '%': + case ' ': + case '+': + dst[dpos++] = '%'; + hi = (c & 0xf0) >> 4; + dst[dpos++] = (hi > 9) ? 'A' + hi - 10 : '0' + hi; + lo = (c & 0x0f); + dst[dpos++] = (lo > 9) ? 'A' + lo - 10 : '0' + lo; + break; + + default: + if (c < ' ' || c > 127) + { + dst[dpos++] = '%'; + hi = (c & 0xf0) >> 4; + dst[dpos++] = (hi > 9) ? 'A' + hi - 10 : '0' + hi; + lo = (c & 0x0f); + dst[dpos++] = (lo > 9) ? 'A' + lo - 10 : '0' + lo; + } + else + { + dst[dpos++] = c; + } + break; + } + } + [d setLength: dpos]; + return d; +} + +- (unsigned) encodeURLEncodedForm: (NSDictionary*)dict + into: (NSMutableData*)data +{ + CREATE_AUTORELEASE_POOL(arp); + NSEnumerator *keyEnumerator; + id key; + unsigned valueCount = 0; + NSMutableData *md = [NSMutableData dataWithCapacity: 100]; + + keyEnumerator = [dict keyEnumerator]; + while ((key = [keyEnumerator nextObject]) != nil) + { + id values = [dict objectForKey: key]; + NSData *keyData; + NSEnumerator *valueEnumerator; + id value; + + if ([key isKindOfClass: [NSData class]] == YES) + { + keyData = key; + } + else + { + key = [key description]; + keyData = [key dataUsingEncoding: NSUTF8StringEncoding]; + } + [md setLength: 0]; + escapeData([keyData bytes], [keyData length], md); + keyData = md; + + if ([values isKindOfClass: [NSArray class]] == NO) + { + values = [NSArray arrayWithObject: values]; + } + + valueEnumerator = [values objectEnumerator]; + + while ((value = [valueEnumerator nextObject]) != nil) + { + NSData *valueData; + + if ([data length] > 0) + { + [data appendBytes: "&" length: 1]; + } + [data appendData: keyData]; + [data appendBytes: "=" length: 1]; + if ([value isKindOfClass: [NSData class]] == YES) + { + valueData = value; + } + else + { + value = [value description]; + valueData = [value dataUsingEncoding: NSUTF8StringEncoding]; + } + escapeData([valueData bytes], [valueData length], data); + valueCount++; + } + } + RELEASE(arp); + return valueCount; +} + - (NSString*) description { return [NSString stringWithFormat: @"%@ on %@(%@), %u of %u sessions active,"