More CF HTTP streams (Re: CFReadStreamGetBuffer doesn't work for HTTP streams?)
More CF HTTP streams (Re: CFReadStreamGetBuffer doesn't work for HTTP streams?)
- Subject: More CF HTTP streams (Re: CFReadStreamGetBuffer doesn't work for HTTP streams?)
- From: Tommy Knowlton <email@hidden>
- Date: Wed, 10 Jul 2002 00:34:31 -0600
Thanks, Becky. That makes good sense, and indeed, I have abandoned
trying to use CFReadStreamGetBuffer for CFHTTPReadStreams.
Now for another CFNetwork question: how does
CFHTTPMessageAddAuthentication() work? In my readStreamCallback function
(asynchronous reading on the CFRunLoop), I have the following code:
// other cases above might 'goto END_OF_STREAM' under certain
circumstances
END_OF_STREAM:
case kCFStreamEventEndEncountered:
// capture the response headers, close the stream (unregister from
the runloop and release the stream).
// 'handle' is an 'ADURLHandle *', my personal HTTP handling
subclass of 'NSURLHandle'
if ([handle tryLockStreamLock]) // sends '-tryLock' to
'_streamLock', an 'NSLock *'
{
int statusCode = 0;
NSString *statusLine = nil;
CFHTTPMessageRef responseHeaders =
(CFHTTPMessageRef)CFReadStreamCopyProperty(readStream,
kCFStreamPropertyHTTPResponseHeader);
if (responseHeaders != NULL)
{
if (CFHTTPMessageIsHeaderComplete(responseHeaders))
{
// store the properties obtained from the response
header, into the ADURLHandle's dictionary
[handle writeProperty:[(NSDictionary
*)CFHTTPMessageCopyAllHeaderFields(responseHeaders) autorelease]
forKey:kADURLHandleHTTPResponseHeadersKey];
statusCode =
CFHTTPMessageGetResponseStatusCode(responseHeaders);
[handle writeProperty:[NSNumber numberWithInt:statusCode]
forKey:kADURLHandleHTTPResponseStatusCodeKey];
statusLine = [(NSString
*)CFHTTPMessageCopyResponseStatusLine(responseHeaders) autorelease];
[handle writeProperty:statusLine
forKey:kADURLHandleHTTPResponseStatusLineKey];
}
// might not be done with 'responseHeaders', but ref count
correctly.
[(id)responseHeaders autorelease];
}
[handle unlockStreamLock];
[handle closeStream]; // close, unregister, release, and
nullify the CFReadStreamRef
// doing all that might not be the
death of the current RunLoop,
// because we might attach another
stream, created below.
if (//(statusCode >= 200) &&
(statusCode < 400)) // I know, I've got yet to deal with
3xx redirect.
{
[handle didLoadBytes:nil
loadComplete:YES];
}
else if ((statusCode == 401) ||
(statusCode == 407))
{
// retry the request...
// as CFNetwork documentation says, close the stream (done),
// followed by 'CFHTTPMessageAddAuthentication' with the
original
// messageRef, followed by create and open a new stream with
the same
// messageRef (that was modified by
'CFHTTPMessageAddAuthentication').
NSCAssert((CFHTTPMessageAddAuthentication([handle message],
responseHeaders,
CFSTR("me"),
CFSTR("myProxyPassword"),
NULL,
(statusCode ==
407))),
@"Failed to add auth to my message.");
// THE ASSERTION ALWAYS FAILS. WHY?
[handle createAndOpenStream]; //
'CFReadStreamCreateForHTTPRequest', ask it to
//
'CFHTTPReadStreamSetRedirectsAutomatically',
// attach it to the RunLoop,
open the stream. Uses _streamLock.
}
else
{
[handle backgroundLoadDidFailWithReason:statusLine];
}
}
break;
Hopefully that's not too hard to follow. The point is, I'm implementing
an NSURLHandle subclass by using CFNetwork. The advantages that this
gives me are 1) auto-proxy-auth behavior (if I can get the thing above
to work) and 2) auto-redirect behavior. Which also I have not gotten to
work for me. Keep reading, if you please.
My question, of course, is "why does the assertion fail?"
I believe that I'm using the 'CFHTTPMessageAddAuthentication' call
correctly as explained in CFNetwork.pdf in my
/Developer/Documentation/Networking/CFNetwork folder. It's dated October
2001, which is as recent as what's on Apple's website. (Respondent
performs a quick double check to verify that assertion).
http://developer.apple.com/techpubs/macosx/Networking/CFNetwork/CFNetwork.
pdf is indeed dated October 2001.
Has anyone seen this API in action? Am I passing an incorrect second
argument? What am I supposed to pass for the second argument?
Also, 'CFHTTPReadStreamSetRedirectsAutomatically(_stream, YES)' seems
not to work for a stream that is read asynchronously (I haven't yet
tried it while reading the stream in a poll-loop). I wonder if anyone
out there has successfully used that API, who can offer me some advice
how to see it win? I wonder if the fact I'm trying to POST instead of
GET hurts my chances? Basically, the design of the web site is such that
a well-formed POST results in a redirect response.
I'm grateful to anybody who's willing to offer me any suggestions.
Especially if your suggestion works! :^)
On Monday, July 8, 2002, at 11:09 PM, macnetworkprog-
email@hidden wrote:
Message: 12
Date: Mon, 8 Jul 2002 17:07:08 -0700
Subject: Re: CFReadStreamGetBuffer doesn't work for HTTP streams?
Cc: email@hidden
To: Tommy Knowlton <email@hidden>
From: Becky Willrich <email@hidden>
CFReadStreamGetBuffer is an optional optimization a la
CFStringGetCStringPtr - it will only return non-NULL if the underlying
stream supports it and if a convenient buffer is on-hand. If you want
to use it, you should always have code that will fall-back to calling
CFReadStreamRead() (which every read stream must support):
// I'm glossing over the details for managing the length of the
buffer...
if (myBuf = CFReadStreamGetBuffer(stream)) {
handleBuffer(myBuf);
} else {
// GetBuffer not supported for this stream
UInt8 buf[BUFSIZE];
CFReadStreamRead(stream, buf, BUFSIZE);
handleBuffer(buf);
}
REW
On Friday, July 5, 2002, at 09:08 AM, Tommy Knowlton wrote:
On my 10.1.5 development system, I seem to be experiencing that
CFReadStreamGetBuffer always writes 0 into its out parameter,
numBytesRead. I've tried negative, zero, and positive values for the
maxBytesToRead in parameter, all with the same result. I am guarding
my callback's kCFStreamEventHasBytesAvailable case with a call to
CFReadStreamHasBytesAvailable (because I believe this is a low-cost
way to guard against other bugs in CFNetwork), so I "know" there are
bytes there before I call CFReadStreamGetBuffer.
Does anyone know any "tricks" to correctly using CFReadStreamGetBytes?
Kind regards,
--Tk!
_______________________________________________
macnetworkprog mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/macnetworkprog
Do not post admin requests to the list. They will be ignored.
--__--__--
Kind regards,
--
Tommy Knowlton
_______________________________________________
macnetworkprog mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/macnetworkprog
Do not post admin requests to the list. They will be ignored.