Mac Developer (Australia): Mac Example --URL Access Manager POST HTTP submission
Source code
A source code example of how to use the URL Access Manager to submit user application data to a web site and to receive the response. The transaction happens in one go and it will it keep the application tied up until its finished. This approach is not suitable for transferring large amounts of data such as files.
The URL Access Manager does have an asynchronous mode that gives greater control during the transfer and it is more suitable for downloading files such as web pages. However this is very difficult to use due to undocumented behaviour and bugs.The MacOS X version behaves differently from the MacOS 9 version, so code written for 9 will not work on X without major changes.
The first tricky part for a novice getting the URL Access Manager to work is that the data that it requires can be Pascal strings, c strings or memory buffers or whatever. It's important to get the number of bytes required by the API call correct. Do you "include the terminator or not" is the question that needs to be answered.
The code below is used as Mac code within a cross-platform application, hence the reference to Windows code. As mentioned above notice the importance of getting the memory count correct. This is done by using sizeof rather than strlen.
You should be aware that the URL Access Manager is now deprecated by Apple in favour of the Core Foundation APIs on MacOS X.
Comments or corrections welcome. Send an email to farad'aty'farad.com.au.
|
/*
---------------------------------------------------------------------
*/
OSStatus
PerformHTTPPost(
const char* inURL,
char* inURLEncodedQuery,
Size inQueryLength)
{
OSStatus status = noErr;
// Step over the leading "\r\n"
// that was put there the keep the
// screwy Windows code happy.
inURLEncodedQuery += 2;
inQueryLength -= 2;
// Specify the URL in a urlReference
URLReference urlReference;
status = URLNewReference(
inURL,
&urlReference);
if(status != noErr)
{
return status;
}
char userAgent[] = "Mozilla/4.03 [en] (Win95; I)"; // c-string
Size userAgentLength = sizeof(userAgent);
status = URLSetProperty(
urlReference,
kURLHTTPUserAgent,
userAgent,
userAgentLength);
if(status != noErr)
{
return status;
}
// Load the urlReference with the POST data
// Specify the request method
char postMethod[] = "POST";
Size methodLength = sizeof(postMethod);
status = URLSetProperty(
urlReference,
kURLHTTPRequestMethod,
postMethod,
methodLength);
if(status != noErr)
{
return status;
}
char contentType[] = "Content-Type:application"
"/x-www-form-urlencoded"; // c-string
Size contentTypeLength = sizeof(contentType);
status = URLSetProperty(
urlReference,
kURLHTTPRequestHeader,
contentType,
contentTypeLength);
if(status != noErr)
{
return status;
}
// Specify the request body.
status = URLSetProperty(
urlReference,
kURLHTTPRequestBody,
inURLEncodedQuery,
inQueryLength);
if(status != noErr)
{
throw status;
}
// Download remote data into into memory, not a file.
FSSpec * destination = NULL;
Handle destinationHandle = NewHandle(0);
//URLOpenFlags openFlags = kURLDisplayProgressFlag;
URLOpenFlags openFlags = 0;
URLSystemEventUPP eventProc = NULL;
void * userContext = NULL;
status = URLDownload (
urlReference,
destination,
destinationHandle,
openFlags,
eventProc,
userContext);
// Convert return download data to a c-string.
UInt32 dataLength = GetHandleSize(destinationHandle);
if(!(dataLength > 0))
{
return MemError();
}
SetHandleSize(destinationHandle, dataLength + 1);
(*destinationHandle)[dataLength] = '\0';
// Check for HTTP status error codes.
// kURLHTTPRespHeader c-string.
// kURLStatusString Pascal string
char httpStatus[1024] = "";
status = URLGetProperty(
urlReference,
kURLHTTPRespHeader,
httpStatus,
sizeof(httpStatus));
if(status != noErr)
{
return status;
}
int httpStatusCode = 0;
char httpStatusMessage[1024] = "";
sscanf(httpStatus, "HTTP/1.1 %d %[^\r]\r\n", "
"&httpStatusCode, httpStatusMessage);
if(httpStatusCode == 200)
{
// Analyse data returned by PHP script
if(strstr(*destinationHandle, "Error") == NULL
&& strstr(*destinationHandle, "error") == NULL)
{
MessageBox(
NULL,
*destinationHandle,
"Submission Success",
MB_ICONINFORMATION);
}
else
{
MessageBox(
NULL,
*destinationHandle,
"Server Error",
MB_ICONINFORMATION);
}
}
else
{
MessageBox(
NULL,
httpStatusMessage,
"HTTP Error",
MB_ICONINFORMATION);
}
// Clean up
DisposeHandle(destinationHandle);
status = URLDisposeReference(urlReference);
if(status != noErr)
{
return status;
}
return status;
}
|