1/*
2 * cgGet.cpp - simplified interface to use CFNetwork to do one
3 * HTTP or HTTPS GET transaction.
4 */
5
6#include "cfSimpleGet.h"
7#include <CoreServices/CoreServices.h>
8
9#define BUFSIZE	1024
10
11#define DEBUG_PRINT	0
12#if		DEBUG_PRINT
13#define dprintf(args...)	printf(args)
14#else
15#define dprintf(args...)
16#endif
17
18CFDataRef cfSimpleGet(
19	const char 	*url)
20{
21	CFURLRef cfUrl = NULL;
22	CFMutableDataRef rtnData = NULL;
23	CFReadStreamRef rdStrm = NULL;
24	CFHTTPMessageRef myReq = NULL;
25	Boolean brtn;
26	UInt8 rbuf[BUFSIZE];
27	CFIndex irtn;
28	bool isOpen = false;
29	CFStreamStatus rsStat;
30
31	cfUrl = CFURLCreateWithBytes(kCFAllocatorDefault,
32		(UInt8 *)url, strlen(url), kCFStringEncodingASCII, NULL);
33	if(cfUrl == NULL) {
34		printf("***Error creating URL for %s.\n", url);
35		return NULL;
36	}
37	myReq = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
38		CFSTR("GET"), cfUrl, kCFHTTPVersion1_0);
39	if(myReq == NULL) {
40		printf("***Error creating HTTP msg for %s.\n", url);
41		goto errOut;
42	}
43	/* no msg body, no headers */
44
45	rdStrm = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, myReq);
46	if(rdStrm == NULL) {
47		printf("***Error creating CFReadStream for %s.\n", url);
48		goto errOut;
49	}
50	dprintf("...opening rd stream for %s\n", url);
51	brtn = CFReadStreamOpen(rdStrm);
52	if(!brtn) {
53		printf("***Error (1) opening CFReadStream for %s.\n", url);
54		goto errOut;
55	}
56
57	/* wait for open */
58	do {
59		rsStat = CFReadStreamGetStatus(rdStrm);
60		switch(rsStat) {
61			case kCFStreamStatusError:
62				printf("***Error (2) opening CFReadStream for %s.\n", url);
63				goto errOut;
64			case kCFStreamStatusAtEnd:
65				printf("***Unexpected EOF while opening %s\n", url);
66				goto errOut;
67			case kCFStreamStatusClosed:
68				printf("***Unexpected close while opening %s\n", url);
69				goto errOut;
70			case kCFStreamStatusNotOpen:
71			case kCFStreamStatusOpening:
72				/* wait some more */
73				break;
74			case kCFStreamStatusOpen:
75			case kCFStreamStatusReading:
76			case kCFStreamStatusWriting:
77				isOpen = true;
78				break;
79			default:
80				printf("***Unexpected status while opening %s\n", url);
81				goto errOut;
82		}
83	} while(!isOpen);
84	dprintf("...rd stream for %s open for business\n", url);
85
86	/* go */
87	rtnData = CFDataCreateMutable(kCFAllocatorDefault, 0);
88	do {
89		irtn = CFReadStreamRead(rdStrm, rbuf, BUFSIZE);
90		if(irtn == 0) {
91			/* end of stream, normal exit */
92			isOpen = false;
93			dprintf("...EOF on rd stream for %s\n", url);
94		}
95		else if(irtn < 0) {
96			/* FIXME - how to tell caller? */
97			printf("***Error reading %s\n", url);
98			isOpen = false;
99		}
100		else {
101			dprintf("   ...read %d bytes from %s\n", (int)irtn, url);
102			CFDataAppendBytes(rtnData, rbuf, irtn);
103		}
104	} while(isOpen);
105errOut:
106	if(myReq) {
107		CFRelease(myReq);
108	}
109	if(rdStrm) {
110		CFRelease(rdStrm);
111	}
112	if(cfUrl) {
113		CFRelease(cfUrl);
114	}
115	if(rtnData) {
116		/* error on zero bytes read */
117		if(CFDataGetLength(rtnData) == 0) {
118			printf("***No data read from %s\n", url);
119			CFRelease(rtnData);
120			rtnData = NULL;
121		}
122	}
123	return rtnData;
124}
125
126
127