Safer debug logging for http request/response

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@38946 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2015-08-29 20:12:33 +00:00
parent ec4431318e
commit 574c83e0bf
4 changed files with 130 additions and 57 deletions

View file

@ -1,6 +1,9 @@
2015-08-29 Richard Frith-Macdonald <rfm@gnu.org>
* Source/Additions/GSMime.m: Improve descriptions for debug.
* Source/Additions/NSData+GNUstepBase.m: Add escaped representation.
* Source/GSHTTPURLHandle.m: Use escaped text format for debug log
(and plist armored format) to ensure that we safely log binary data
2015-08-24 Richard Frith-Macdonald <rfm@gnu.org>

View file

@ -47,6 +47,18 @@ extern "C" {
*/
+ (id) dataWithRandomBytesOfLength: (NSUInteger)length;
/** Returns an NSString object containing a backslash escaped representation
* of the receiver.
*/
- (NSString*) escapedRepresentation;
/**
* Returns a buffer containing an ASCII backslash escaped representation
* of the receiver, (and optionally the size of the buffer excluding
* the trailing nul terminator).
*/
- (char*) escapedRepresentation: (NSUInteger*)length;
/** Returns data formed by gunzipping the contents of the receiver.<br />
* If the receiver did not contain data produced by gzip, this method
* simply returns the receiver.<br />
@ -70,23 +82,22 @@ extern "C" {
*/
- (BOOL) isGzipped;
/**
* Returns an NSString object containing an ASCII hexadecimal representation
/** Returns an NSString object containing an ASCII hexadecimal representation
* of the receiver. This means that the returned object will contain
* exactly twice as many characters as there are bytes as the receiver,
* as each byte in the receiver is represented by two hexadecimal digits.<br />
* The high order four bits of each byte is encoded before the low
* order four bits. Capital letters 'A' to 'F' are used to represent
* values from 10 to 15.<br />
* If you need the hexadecimal representation as raw byte data, use code
* like -
* <example>
* hexData = [[sourceData hexadecimalRepresentation]
* dataUsingEncoding: NSASCIIStringEncoding];
* </example>
* values from 10 to 15.
*/
- (NSString*) hexadecimalRepresentation;
/** Returns a buffer containing an ASCII string with a nul terminated
* hexadecimal representation of the receiver, (and optionally the size
* of the buffer excluding the trailing nul terminator).
*/
- (char*) hexadecimalRepresentation: (NSUInteger*)length;
/**
* Initialises the receiver with the supplied string data which contains
* a hexadecimal coding of the bytes. The parsing of the string is

View file

@ -116,33 +116,107 @@ randombytes(uint8_t *buf, unsigned len)
return AUTORELEASE(d);
}
/**
* Returns an NSString object containing an ASCII hexadecimal representation
* of the receiver. This means that the returned object will contain
* exactly twice as many characters as there are bytes as the receiver,
* as each byte in the receiver is represented by two hexadecimal digits.<br />
* The high order four bits of each byte is encoded before the low
* order four bits. Capital letters 'A' to 'F' are used to represent
* values from 10 to 15.<br />
* If you need the hexadecimal representation as raw byte data, use code
* like -
* <example>
* hexData = [[sourceData hexadecimalRepresentation]
* dataUsingEncoding: NSASCIIStringEncoding];
* </example>
*/
- (NSString*) escapedRepresentation
{
char *buf;
NSUInteger len;
NSString *string;
buf = [self escapedRepresentation: &len];
string = [[NSString alloc] initWithBytesNoCopy: buf
length: len
encoding: NSASCIIStringEncoding
freeWhenDone: YES];
return AUTORELEASE(string);
}
- (char*) escapedRepresentation: (NSUInteger*)length
{
const uint8_t *bytes = (const uint8_t*)[self bytes];
uint8_t *buf;
NSUInteger count = [self length];
NSUInteger size = count + 1;
NSUInteger index;
NSUInteger pos;
for (index = 0; index < count; index++)
{
uint8_t b = bytes[index];
if ('\n' == b) size++;
else if ('\r' == b) size++;
else if ('\t' == b) size++;
else if ('\\' == b) size++;
else if (!isprint(b)) size += 3;
}
buf = (uint8_t*)malloc(size);
for (pos = index = 0; index < count; index++)
{
uint8_t b = bytes[index];
if ('\n' == b)
{
buf[pos++] = '\\';
buf[pos++] = 'n';
}
else if ('\r' == b)
{
buf[pos++] = '\\';
buf[pos++] = 'r';
}
else if ('\t' == b)
{
buf[pos++] = '\\';
buf[pos++] = 't';
}
else if ('\\' == b)
{
buf[pos++] = '\\';
buf[pos++] = '\\';
}
else if (!isprint(b))
{
sprintf((char*)&buf[pos], "\\x%02x", b);
pos += 4;
}
else
{
buf[pos++] = b;
}
}
buf[pos] = '\0';
if (0 != length)
{
*length = pos;
}
return (char*)buf;
}
- (NSString*) hexadecimalRepresentation
{
char *buf;
NSUInteger len;
NSString *string;
buf = [self hexadecimalRepresentation: &len];
string = [[NSString alloc] initWithBytesNoCopy: buf
length: len
encoding: NSASCIIStringEncoding
freeWhenDone: YES];
return AUTORELEASE(string);
}
- (char*) hexadecimalRepresentation: (NSUInteger*)length
{
static const char *hexChars = "0123456789ABCDEF";
unsigned slen = [self length];
unsigned dlen = slen * 2;
const unsigned char *src = (const unsigned char *)[self bytes];
char *dst = (char*)NSZoneMalloc(NSDefaultMallocZone(), dlen);
char *dst;
unsigned spos = 0;
unsigned dpos = 0;
NSData *data;
NSString *string;
dst = (char*)malloc(dlen + 1);
while (spos < slen)
{
unsigned char c = src[spos++];
@ -150,12 +224,12 @@ randombytes(uint8_t *buf, unsigned len)
dst[dpos++] = hexChars[(c >> 4) & 0x0f];
dst[dpos++] = hexChars[c & 0x0f];
}
data = [NSData allocWithZone: NSDefaultMallocZone()];
data = [data initWithBytesNoCopy: dst length: dlen];
string = [[NSString alloc] initWithData: data
encoding: NSASCIIStringEncoding];
RELEASE(data);
return AUTORELEASE(string);
dst[dpos] = '\0';
if (0 != length)
{
*length = dpos;
}
return dst;
}
- (NSData*) gunzipped

View file

@ -43,6 +43,7 @@
#import "Foundation/NSValue.h"
#import "GNUstepBase/GSMime.h"
#import "GNUstepBase/GSLock.h"
#import "GNUstepBase/NSData+GNUstepBase.h"
#import "GNUstepBase/NSString+GNUstepBase.h"
#import "GNUstepBase/NSURL+GNUstepBase.h"
#import "NSCallBacks.h"
@ -230,36 +231,20 @@ static Class sslClass = 0;
static void
debugRead(GSHTTPURLHandle *handle, NSData *data)
{
int len = (int)[data length];
const char *ptr = (const char*)[data bytes];
int pos;
unsigned len = (unsigned)[data length];
char *esc = [data escapedRepresentation: 0];
for (pos = 0; pos < len; pos++)
{
if (0 == ptr[pos])
{
NSLog(@"Read for %p of %d bytes - %@", handle, len, data);
return;
}
}
NSLog(@"Read for %p of %d bytes - '%*.*s'", handle, len, len, len, ptr);
NSLog(@"Read for %p of %u bytes - '%s'\n%@", handle, len, esc, data);
free(esc);
}
static void
debugWrite(GSHTTPURLHandle *handle, NSData *data)
{
int len = (int)[data length];
const char *ptr = (const char*)[data bytes];
int pos = len;
unsigned len = (unsigned)[data length];
char *esc = [data escapedRepresentation: 0];
for (pos = 0; pos < len; pos++)
{
if (0 == ptr[pos])
{
NSLog(@"Write for %p of %d bytes - %@", handle, len, data);
return;
}
}
NSLog(@"Write for %p of %d bytes -'%*.*s'", handle, len, len, len, ptr);
NSLog(@"Write for %p of %u bytes - '%s'\n%@", handle, len, esc, data);
free(esc);
}
+ (NSURLHandle*) cachedHandleForURL: (NSURL*)newUrl