palm-os-sdk/PalmOne/Samples/_HTTPLibTest/Src/httptest.c

551 lines
14 KiB
C

#include <PalmOS.h>
#include <68K\Hs.h>
#include <StringMgr.h>
#include "peer.h"
#include "httptest.h"
#include "HTTPLibTest.h" // application resource defines
#include "AppStdIO.h"
#define DOWNLOAD_BUFFER_SIZE (8192)
#define __SKIP_WRITE 0
/*********************************************************************
* Local variables
*********************************************************************/
#if 0
static Char *ProxyHost = "10.0.0.112";
static Int32 ProxyPort = 8001;
static Char *NoProxyHost = "";
#endif
static UInt16 gRefNum = sysInvalidRefNum;
static HS_HTTPLibHandle gLibHandle = NULL;
static HS_HTTPLibAppInfo gAppInfo;
static HS_HTTPLibNetLibInfo gNetLibInfo;
static HS_HTTPLibPeer gPeer;
static Char title[50];
#define FrmSetTitle(...) if(0){}
UInt32 gstartTicks;
UInt32 gstopTicks;
UInt32 glatencyTicks;
Boolean gErrorFlag = false;
/*********************************************************************
* Function declaration
*********************************************************************/
Int32 PrvTunnelingCallback(HS_HTTPLibStream in_stream, Char* buf, Int32 len, void *aux);
/*********************************************************************
* Data structure
*********************************************************************/
enum
{
kDownloadState_None,
kDownloadState_Request,
kDownloadState_RequestWithPost,
kDownloadState_RequestWithChunkEncoding,
kDownloadState_ReceiveHeader,
kDownloadState_ReceiveContent,
kDownloadState_Close,
kDownloadState_Done,
kDownloadState_Error,
kDownloadState_Cancel,
kDownloadState_Abort,
kDownloadState_Max
};
typedef struct
{
HS_HTTPLibStream fHTTPStream;
Int32 fState;
Int32 fCurrentLength;
Int32 fContentLength;
Char *fBuffer;
Int32 fBufferLen;
Char *fPostData;
Int32 fPostDataLen;
Int32 fPostedLen;
} DownloadInfo;
/*********************************************************************
* Functions
*********************************************************************/
Err PrvHTTPLibInitialize(void)
{
Err err = errNone;
/* load the library */
if( gRefNum == sysInvalidRefNum ) {
err = SysLibFind(HS_HTTPLibName, &gRefNum);
if (err) {
err = SysLibLoad(HS_HTTPLibDBType, HS_HTTPLibID, &gRefNum);
}
if (err) {
return err;
}
}
err = HS_HTTPLibOpen(gRefNum);
/* gPeer */
MemSet(&gPeer, sizeof(HS_HTTPLibPeer), 0);
gPeer.HS_HTTPLibPeerTCPOpen = &PrvTCPOpen;
gPeer.HS_HTTPLibPeerTCPClose = &PrvTCPClose;
gPeer.HS_HTTPLibPeerTCPIsConnected = &PrvTCPIsConnected;
gPeer.HS_HTTPLibPeerTCPConnect = &PrvTCPConnect;
gPeer.HS_HTTPLibPeerTCPRead = &PrvTCPRead;
gPeer.HS_HTTPLibPeerTCPWrite = &PrvTCPWrite;
gPeer.HS_HTTPLibPeerTCPCanReadWrite = &PrvTCPCanReadWrite;
gAppInfo.maxSockets = 3;
gAppInfo.isForeground = true;
gAppInfo.cookieMaxJarSize = (UInt16)300 * (UInt16)1024;
PrvPeerInitialize();
gLibHandle = HS_HTTPLibInitialize(gRefNum, &gAppInfo, &gNetLibInfo, &gPeer);
/* set callbacks */
//HS_HTTPLibSetSSLServerCertConfirmProc(gRefNum, gLibHandle, &test_confirm_cb, (HS_HTTPLibOpaque)gLibHandle);
//HS_HTTPLibSetTunnelingCallback(gRefNum, gLibHandle, &PrvTunnelingCallback, NULL);
/* set timeout time */
HS_HTTPLibSetConnectTimeOut(gRefNum, gLibHandle, -1);
HS_HTTPLibSetReqTimeOut(gRefNum, gLibHandle, -1);
HS_HTTPLibSetRspTimeOut(gRefNum, gLibHandle, 10 * 1000);
/* set proxy info */
//HS_HTTPLibSetProxy(gRefNum, gLibHandle, ProxyHost, StrLen(ProxyHost), ProxyPort, ProxyPort, NoProxyHost, 0);
//HS_HTTPLibSetUseProxy(gRefNum, gLibHandle, true);
return err;
}
Err PrvHTTPLibFinalize(void)
{
Err err;
UInt16 count;
HS_HTTPLibFinalize(gRefNum, gLibHandle);
PrvPeerFinalize();
err = HS_HTTPLibClose(gRefNum, &count);
/* unload the library */
if( gRefNum != sysInvalidRefNum ){
SysLibRemove(gRefNum);
gRefNum = sysInvalidRefNum;
}
return err;
}
Int32
PrvTunnelingCallback(HS_HTTPLibStream in_stream, Char* buf, Int32 len, void *aux)
{
return 0;
}
#if __SKIP_WRITE
/*********************************************************************
* Store Functions
*********************************************************************/
static void
set_text(Char *str)
{
FileHand file;
UInt32 mode = fileModeAppend;
Int32 nwritten = 0;
Err err = errNone;
if (str == NULL) return;
file = FileOpen (0, "httpdata.pdb", 0, 0, mode, &err);
if (file != 0) {
nwritten = FileWrite (file, str, StrLen(str), 1, &err);
FileClose(file);
}
}
#endif
/*********************************************************************
* Download Functions
*********************************************************************/
static Int32
download_open(DownloadInfo *self)
{
return 0;//dummy
}
static Int32
download_write(DownloadInfo *self, Int32 in_len)
{
#if __SKIP_WRITE // this code works, but don't want overhead for throughput test
Char *buffer;
if (in_len == 0) return 0;
buffer = MemPtrNew(in_len);
if (buffer) {
MemMove(buffer, self->fBuffer, in_len);
set_text(buffer);
buffer[in_len] = 0;
MemPtrFree(buffer);
}
#endif
return 0;//dummy
}
static void
download_close(DownloadInfo *self)
{
if(self->fHTTPStream){
HS_HTTPLibStreamClose(gRefNum, self->fHTTPStream ); /* Close HTTP */
HS_HTTPLibStreamDelete(gRefNum, self->fHTTPStream );
self->fHTTPStream = NULL;
}
}
static Int32
download_do_request(DownloadInfo *self)
{
Int32 result;
result = HS_HTTPLibStreamSendRequest(gRefNum, self->fHTTPStream, NULL);
if(result == httpErrorOK){
self->fState = kDownloadState_ReceiveHeader;
}else if(result == httpErrorWouldBlock){
/* do nothing */
}else{
self->fState = kDownloadState_Error;
}
result = httpErrorWouldBlock;
return result;
}
static Int32
download_do_request_withpost(DownloadInfo *self)
{
Int32 result;
Int32 writtenLen;
result = HS_HTTPLibStreamSendRequestWithPostData(gRefNum, self->fHTTPStream, self->fPostData, self->fPostDataLen - self->fPostedLen, &writtenLen, NULL);
if(writtenLen > 0){
self->fPostData += writtenLen;
self->fPostedLen += writtenLen;
}
if(result == httpErrorOK){
self->fState = kDownloadState_ReceiveHeader;
}else if(result == httpErrorWouldBlock){
/* do nothing */
}else{
Char error[30];
StrIToA(error, result);
FrmCustomAlert(ErrorAlert, "request withpost", error, "");
self->fState = kDownloadState_Error;
}
result = httpErrorWouldBlock;
return result;
}
static Int32
download_receive_header(DownloadInfo *self)
{
Int32 result;
Int32 len=0;
//HS_HTTPLibVHandle hdrH=NULL;
result = HS_HTTPLibStreamReceiveResponse(gRefNum, self->fHTTPStream, NULL, 0, &len, NULL);
//hdrH = HS_HTTPLibStreamGetResponseHeader(gRefNum, self->fHTTPStream);
switch(result){
case httpErrorOK:
//self->fState = kDownloadState_ReceiveContent;
case httpErrorWouldBlock:
if(HS_HTTPLibStreamIsHeaderReceived(gRefNum, self->fHTTPStream)){
self->fState = kDownloadState_ReceiveContent;
self->fContentLength = HS_HTTPLibStreamGetContentLength(gRefNum, self->fHTTPStream);
}
else
{
Int32 hLen;
hLen = HS_HTTPLibStreamGetResponseHeaderLength(gRefNum, self->fHTTPStream);
// when hLen > 0, start content timer
// everything up to here is latency!
glatencyTicks = TimGetTicks();
}
break;
default:
self->fState = kDownloadState_Error;
break;
}
result = httpErrorWouldBlock;
return result;
}
static Int32
download_receive_content(DownloadInfo *self)
{
Int32 result;
Int32 len;
result = HS_HTTPLibStreamReceiveResponse(gRefNum, self->fHTTPStream,
self->fBuffer, self->fBufferLen, &len, NULL);
switch(result){
case httpErrorOK:
case httpErrorWouldBlock:
case httpErrorIOSleep:
if(len > 0){
download_write(self, len);
self->fCurrentLength += len;
} else
{
if(len == 0){
download_write(self, len);/* for ExchangeManager GUI */
}
}
if(self->fContentLength > 0){
if(self->fContentLength <= self->fCurrentLength){
self->fState = kDownloadState_Close;
}
}
if(result == httpErrorOK){
self->fContentLength += self->fCurrentLength;
self->fState = kDownloadState_Close;
}
break;
default:
self->fState = kDownloadState_Error;
break;
}
result = httpErrorWouldBlock;
return result;
}
static Int32
download_receive_close(DownloadInfo *self)
{
download_close(self);
self->fState = kDownloadState_Done;
return httpErrorWouldBlock;
}
static Int32
download_receive_done(DownloadInfo *self)
{
return httpErrorOK;
}
static Int32
download_receive_error(DownloadInfo *self)
{
download_close(self);
self->fState = kDownloadState_Abort;
gErrorFlag = true;
return httpErrorWouldBlock;
}
static Int32
download_receive_cancel(DownloadInfo *self)
{
download_close(self);
self->fState = kDownloadState_Abort;
return httpErrorWouldBlock;
}
static Int32
download_receive_abort(DownloadInfo *self)
{
return httpErrorOK;
}
static DownloadInfo *
DonwloadInfoNew(Char *urlP)
{
DownloadInfo *infoP = NULL;
infoP = (DownloadInfo *)MemPtrNew(sizeof(DownloadInfo));
if(!infoP) return NULL;
MemSet(infoP, sizeof(DownloadInfo), 0);
infoP->fState = kDownloadState_Request;
infoP->fCurrentLength = 0;
infoP->fContentLength = 0;
infoP->fBufferLen = DOWNLOAD_BUFFER_SIZE;
infoP->fPostDataLen = 0;
infoP->fPostData = NULL;
infoP->fPostedLen = 0;
infoP->fBuffer = MemPtrNew(DOWNLOAD_BUFFER_SIZE);
infoP->fHTTPStream = HS_HTTPLibStreamNew(gRefNum, gLibHandle);
if(!infoP->fHTTPStream) goto error;
download_open(infoP);
return infoP;
error:
if(infoP->fBuffer){
MemPtrFree(infoP->fBuffer);
}
if(infoP->fHTTPStream){
HS_HTTPLibStreamClose(gRefNum, infoP->fHTTPStream); /* Close HTTP */
HS_HTTPLibStreamDelete(gRefNum, infoP->fHTTPStream);
}
MemPtrFree(infoP);
return NULL;
}
static void
DonwloadInfoFree(DownloadInfo *self)
{
if(!self) return;
if(self->fBuffer){
MemPtrFree(self->fBuffer);
}
if(self->fHTTPStream){
HS_HTTPLibStreamClose(gRefNum, self->fHTTPStream); /* Close HTTP */
HS_HTTPLibStreamDelete(gRefNum, self->fHTTPStream);
}
MemPtrFree(self);
}
static Int32
DownloadInfoProgress(DownloadInfo *self)
{
Int32 result = httpErrorOK;
switch(self->fState){
case kDownloadState_None:
break;
case kDownloadState_Request:
FrmSetTitle(FrmGetFormPtr(MainForm), NULL);
StrCopy(title, "Requesting");
result = download_do_request(self);
break;
case kDownloadState_RequestWithPost:
FrmSetTitle(FrmGetFormPtr(MainForm), NULL);
StrCopy(title, "Requesting w/ post");
result = download_do_request_withpost(self);
break;
case kDownloadState_ReceiveHeader:
FrmSetTitle(FrmGetFormPtr(MainForm), NULL);
StrCopy(title, "Receive Header");
result = download_receive_header(self);
//HsExtTraceText (gTraceContext, kHsExtTraceLevelDevInfo,
// "result: %ld", result);
break;
case kDownloadState_ReceiveContent:
FrmSetTitle(FrmGetFormPtr(MainForm), NULL);
StrCopy(title, "Receive Content");
result = download_receive_content(self);
break;
case kDownloadState_Close:
result = download_receive_close(self);
break;
case kDownloadState_Done:
FrmSetTitle(FrmGetFormPtr(MainForm), NULL);
StrCopy(title, "Done");
result = download_receive_done(self);
break;
case kDownloadState_Error:
FrmSetTitle(FrmGetFormPtr(MainForm), NULL);
StrCopy(title, "Error");
result = download_receive_error(self);
break;
case kDownloadState_Cancel:
FrmSetTitle(FrmGetFormPtr(MainForm), NULL);
StrCopy(title, "Canceling");
result = download_receive_cancel(self);
break;
case kDownloadState_Abort:
result = download_receive_abort(self);
break;
default:
result = httpErrorOK;
break;
}
FrmSetTitle(FrmGetFormPtr(MainForm), title);
return result;
}
void
PrvHTTPLibTestGet(Char *urlP)
{
DownloadInfo *self;
Int32 result;
UInt32 secs;
UInt32 msecs;
UInt32 ticks;
UInt32 ticksPerSecond=SysTicksPerSecond();
UInt32 thruput;
self = DonwloadInfoNew(urlP);
result = HS_HTTPLibStreamCreateRequest(gRefNum, self->fHTTPStream, httpMethodGET,
urlP, StrLen(urlP), "", 0, "", 0,
httpVersion_1_1, false, false, httpSSLFlagConnV2V3TLS);
// override the "gzip, deflate" default
HS_HTTPLibStreamAddHeader(gRefNum, self->fHTTPStream, httpHeaderIDAcceptEncoding, "*/*", 3);
result = -1;
// start timer
gstartTicks = TimGetTicks ();
gErrorFlag = false;
while(result != httpErrorOK){
result = DownloadInfoProgress(self);
}
// stop timer
gstopTicks = TimGetTicks();
if (!gErrorFlag)
{
secs = (gstopTicks-gstartTicks) / ticksPerSecond;
ticks = (gstopTicks-gstartTicks) % ticksPerSecond;
msecs = (ticks * 1000) / ticksPerSecond;
printf("Total Time : %ld s %ld ms\n", secs, msecs);
secs = (glatencyTicks-gstartTicks) / ticksPerSecond;
ticks = (glatencyTicks-gstartTicks) % ticksPerSecond;
msecs = (ticks * 1000) / ticksPerSecond;
printf("Resp Latency: %ld s %ld ms\n", secs, msecs);
printf("Total Bytes : %ld bytes\n", self->fContentLength);
if (gstopTicks-glatencyTicks){ // Simulator sometimes showed '0' time elapsed
thruput = (self->fContentLength*ticksPerSecond)/(gstopTicks - glatencyTicks);
printf("Throughput : %ld bytes/sec\n", thruput);
}
else
;
}
else
{
;
}
DonwloadInfoFree(self);
}
void
PrvHTTPLibTestPost(Char *urlP, Char *postDataP)
{
DownloadInfo *self;
Int32 result;
self = DonwloadInfoNew(urlP);
result = HS_HTTPLibStreamCreateRequest(gRefNum, self->fHTTPStream, httpMethodPOST,
urlP, StrLen(urlP), "", 0, "", 0,
httpVersion_1_1, false, false, httpSSLFlagConnV2V3TLS);
HS_HTTPLibStreamSetPostData(gRefNum, self->fHTTPStream, httpPostURLENCODED, NULL, StrLen(postDataP));
self->fPostData = postDataP;
self->fPostDataLen = StrLen(postDataP);
self->fState = kDownloadState_RequestWithPost;
result = -1;
while(result != httpErrorOK){
result = DownloadInfoProgress(self);
}
DonwloadInfoFree(self);
}