From 77e8402dd68079c0e245fc8826daf2c6ad334766 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Tue, 26 Sep 2006 16:58:27 +0000 Subject: r18925: Add current snapshot of the ejs-2.0 code. Tridge, will you be incorporating this? (This used to be commit 917af234a8d517f82bd42256a940608a16b988f4) --- .../lib/appweb/ejs-2.0/ejs/system/UNIX/ejsHTTP.c | 488 +++++++++++++++++++++ 1 file changed, 488 insertions(+) create mode 100755 source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsHTTP.c (limited to 'source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsHTTP.c') diff --git a/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsHTTP.c b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsHTTP.c new file mode 100755 index 0000000000..25821f6960 --- /dev/null +++ b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsHTTP.c @@ -0,0 +1,488 @@ +/* + * @file ejsHTTP.c + * @brief HTTP class for the EJ System Object Model + */ +/********************************** Copyright *********************************/ +/* + * Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved. + */ +/********************************** Includes **********************************/ + +#include "ejs.h" + +#if UNUSED +/*********************************** Defines **********************************/ + +#define EJS_WEB_PROPERTY "-web" +#define EJS_HTTP_PROPERTY "-http" + +#define EJS_HTTP_DISPOSED 550 + +/* + * Control structure for one HTTP request structure + */ +typedef struct HTTPControl { + Ejs *ejs; + IWebResp *webResp; + AEECallback *callback; + MprBuf *buf; + EjsVar *thisObj; + char *url; + MprTime requestStarted; + uint timeout; +} HTTPControl; + +/****************************** Forward Declarations **************************/ + +static void cleanup(HTTPControl *hp); +static int createWeb(Ejs *ejs, EjsVar *thisObj); +static void brewCallback(HTTPControl *hp); +static int httpDestructor(Ejs *ejs, EjsVar *vp); +static void httpCallback(HTTPControl *hp, int responseCode); +static int setCallback(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv); + +/******************************************************************************/ +/* + * Constructor + */ + +int ejsHTTPConstructor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv) +{ + if (argc != 0 && argc != 2) { + ejsError(ejs, EJS_ARG_ERROR, + "Bad usage: HTTP([obj = this, method = onComplete]);"); + return -1; + } + + if (createWeb(ejs, thisObj) < 0) { + return -1; + } + + setCallback(ejs, thisObj, argc, argv); + return 0; +} + +/******************************************************************************/ + +static int createWeb(Ejs *ejs, EjsVar *thisObj) +{ + MprApp *app; + void *web; + + app = mprGetApp(ejs); + + /* + * Create one instance of IWeb for the entire application. Do it here + * so only widgets that require HTTP incurr the overhead. + */ + web = mprGetKeyValue(ejs, "bpWeb"); + if (web == 0) { + if (ISHELL_CreateInstance(app->shell, AEECLSID_WEB, &web) != SUCCESS) { + ejsError(ejs, EJS_IO_ERROR, "Can't create IWEB"); + return -1; + } + } + mprSetKeyValue(ejs, "bpWeb", web); + return 0; +} + +/******************************************************************************/ +/************************************ Methods *********************************/ +/******************************************************************************/ +/* + * function setCallback(obj, methodString); + */ + +static int setCallback(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv) +{ + if (argc >= 1) { + ejsSetProperty(ejs, thisObj, "obj", argv[0]); + } else { + ejsSetProperty(ejs, thisObj, "obj", thisObj); + } + + if (argc >= 2) { + ejsSetProperty(ejs, thisObj, "method", argv[1]); + } else { + ejsSetPropertyToString(ejs, thisObj, "method", "onComplete"); + } + + return 0; +} + +/******************************************************************************/ +/* + * function fetch(); + */ + +static int fetchProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv) +{ + HTTPControl *hp; + EjsProperty *pp; + MprApp *app; + IWeb *web; + + if (argc != 1 || !ejsVarIsString(argv[0])) { + ejsError(ejs, EJS_ARG_ERROR, "Bad usage: fetch(url)"); + return -1; + } + + app = mprGetApp(ejs); + web = (IWeb*) mprGetKeyValue(ejs, "bpWeb"); + + /* + * Web options + * + * WEBOPT_USERAGENT (char*) sets user agent + * WEBOPT_HANDLERDATA (void*) + * WEBOPT_CONNECTTIMEOUT (uint) msec + * WEBOPT_CONTENTLENGTH (long) + * WEBOPT_IDLECONNTIMEOUT (int) + * WEBOPT_ACTIVEXACTIONST (uint) Number of active requests + * + * WEBREQUEST_REDIRECT redirect transparently + * + */ + + hp = mprAllocType(ejs, HTTPControl); + if (hp == 0) { + ejsMemoryError(ejs); + return -1; + } + + hp->ejs = ejs; + hp->buf = mprCreateBuf(hp, MPR_BUF_INCR, MPR_MAX_BUF); + if (hp->buf == 0) { + mprFree(hp); + ejsMemoryError(ejs); + return -1; + } + + /* + * We copy thisObj because we need to preserve both the var and the object. + * We pass the var to brewCallback and so it must persist. The call to + * ejsMakeObjPermanent will stop the GC from collecting the object. + */ + hp->thisObj = ejsDupVar(ejs, thisObj, EJS_SHALLOW_COPY); + ejsSetVarName(ejs, hp->thisObj, "internalHttp"); + + /* + * Must keep a reference to the http object + */ + ejsMakeObjPermanent(hp->thisObj, 1); + + /* + * Make a property so we can access the HTTPControl structure from other + * methods. + */ + pp = ejsSetPropertyToPtr(ejs, thisObj, EJS_HTTP_PROPERTY, hp, 0); + ejsMakePropertyEnumerable(pp, 0); + ejsSetObjDestructor(ejs, hp->thisObj, httpDestructor); + + hp->url = mprStrdup(hp, argv[0]->string); + + hp->timeout = ejsGetPropertyAsInteger(ejs, thisObj, "timeout"); + mprGetTime(hp, &hp->requestStarted); + + hp->callback = mprAllocTypeZeroed(hp, AEECallback); + CALLBACK_Init(hp->callback, brewCallback, hp); + + hp->webResp = 0; + IWEB_GetResponse(web, + (web, &hp->webResp, hp->callback, hp->url, + WEBOPT_HANDLERDATA, hp, + WEBOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)", + WEBOPT_CONNECTTIMEOUT, hp->timeout, + WEBOPT_COPYOPTS, TRUE, + WEBOPT_CONTENTLENGTH, 0, + WEBOPT_END)); + + ejsSetPropertyToString(ejs, thisObj, "status", "active"); + + return 0; +} + +/******************************************************************************/ +/* + * Called whenver the http object is deleted. + */ + +static int httpDestructor(Ejs *ejs, EjsVar *thisObj) +{ + HTTPControl *hp; + + /* + * If the httpCallback has run, then this property will not exist + */ + hp = ejsGetPropertyAsPtr(ejs, thisObj, EJS_HTTP_PROPERTY); + + if (hp) { + cleanup(hp); + } + + return 0; +} + +/******************************************************************************/ +/* + * Stop the request immediately without calling the callback + */ + +static int stopProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv) +{ + HTTPControl *hp; + + hp = ejsGetPropertyAsPtr(ejs, thisObj, EJS_HTTP_PROPERTY); + + if (hp) { + cleanup(hp); + } + + return 0; +} + +/******************************************************************************/ +/* + * Brew HTTP callback. Invoked for any return data. + */ + +static void brewCallback(HTTPControl *hp) +{ + Ejs *ejs; + EjsVar *thisObj; + ISource *source; + WebRespInfo *info; + char data[MPR_BUF_INCR]; + int bytes; + + mprAssert(hp); + mprAssert(hp->webResp); + + info = IWEBRESP_GetInfo(hp->webResp); + + if (info == 0) { + mprAssert(info); + /* should not happen */ + return; + } + + ejs = hp->ejs; + thisObj = hp->thisObj; + + if (! WEB_ERROR_SUCCEEDED(info->nCode)) { + ejsSetPropertyToString(ejs, thisObj, "status", "error"); + httpCallback(hp, info->nCode); + return; + } + + if (hp->timeout) { + if (mprGetTimeRemaining(hp, hp->requestStarted, hp->timeout) <= 0) { + ejsSetPropertyToString(ejs, thisObj, "status", "timeout"); + httpCallback(hp, 504); + return; + } + } + + /* + * Normal success + */ + source = info->pisMessage; + mprAssert(source); + + bytes = ISOURCE_Read(source, data, sizeof(data)); + + switch (bytes) { + case ISOURCE_WAIT: // No data yet + ISOURCE_Readable(source, hp->callback); + break; + + case ISOURCE_ERROR: + ejsSetPropertyToString(ejs, thisObj, "status", "error"); + httpCallback(hp, info->nCode); + break; + + case ISOURCE_END: + mprAddNullToBuf(hp->buf); + ejsSetPropertyToString(ejs, thisObj, "status", "complete"); + httpCallback(hp, info->nCode); + break; + + default: + if (bytes > 0) { + if (mprPutBlockToBuf(hp->buf, data, bytes) != bytes) { + ejsSetPropertyToString(ejs, thisObj, "status", "partialData"); + httpCallback(hp, 500); + } + } + ISOURCE_Readable(source, hp->callback); + break; + } +} + +/******************************************************************************/ +/* + * Invoke the HTTP completion method + */ + +static void httpCallback(HTTPControl *hp, int responseCode) +{ + Ejs *ejs; + EjsVar *thisObj, *callbackObj; + MprArray *args; + char *msg; + const char *callbackMethod; + + mprAssert(hp); + mprAssert(hp->webResp); + + thisObj = hp->thisObj; + ejs = hp->ejs; + + ejsSetPropertyToInteger(ejs, thisObj, "responseCode", responseCode); + if (mprGetBufLength(hp->buf) > 0) { + ejsSetPropertyToBinaryString(ejs, thisObj, "responseData", + mprGetBufStart(hp->buf), mprGetBufLength(hp->buf)); + } + + callbackObj = ejsGetPropertyAsVar(ejs, thisObj, "obj"); + callbackMethod = ejsGetPropertyAsString(ejs, thisObj, "method"); + + if (callbackObj != 0 && callbackMethod != 0) { + + args = mprCreateItemArray(ejs, EJS_INC_ARGS, EJS_MAX_ARGS); + mprAddItem(args, ejsDupVar(ejs, hp->thisObj, EJS_SHALLOW_COPY)); + + if (ejsRunMethod(ejs, callbackObj, callbackMethod, args) < 0) { + msg = ejsGetErrorMsg(ejs); + mprError(ejs, MPR_LOC, "HTTP callback failed. Details: %s", msg); + } + ejsFreeMethodArgs(ejs, args); + + } else if (ejsRunMethod(ejs, thisObj, "onComplete", 0) < 0) { + msg = ejsGetErrorMsg(ejs); + mprError(ejs, MPR_LOC, "HTTP onComplete failed. Details: %s", msg); + } + + cleanup(hp); +} + +/******************************************************************************/ +/* + * Cleanup + */ + +static void cleanup(HTTPControl *hp) +{ + Ejs *ejs; + MprApp *app; + int rc; + + mprAssert(hp); + mprAssert(hp->webResp); + + ejs = hp->ejs; + + if (hp->webResp) { + rc = IWEBRESP_Release(hp->webResp); + // mprAssert(rc == 0); + hp->webResp = 0; + } + + if (hp->callback) { + CALLBACK_Cancel(hp->callback); + mprFree(hp->callback); + hp->callback = 0; + } + + /* + * Once the property is deleted, then if the destructor runs, it will + * notice that the EJS_HTTP_PROPERTY is undefined. + */ + ejsDeleteProperty(ejs, hp->thisObj, EJS_HTTP_PROPERTY); + + /* + * Allow garbage collection to work on thisObj + */ + ejsMakeObjPermanent(hp->thisObj, 0); + ejsFreeVar(ejs, hp->thisObj); + + mprFree(hp->buf); + mprFree(hp->url); + + mprFree(hp); + + app = mprGetApp(ejs); + + + ISHELL_SendEvent(app->shell, (AEECLSID) app->classId, EVT_USER, 0, 0); +} + +/******************************************************************************/ +/******************************** Initialization ******************************/ +/******************************************************************************/ + +int ejsDefineHTTPClass(Ejs *ejs) +{ + EjsVar *httpClass; + + httpClass = + ejsDefineClass(ejs, "HTTP", "Object", ejsHTTPConstructor); + if (httpClass == 0) { + return MPR_ERR_CANT_INITIALIZE; + } + + /* + * Define the methods + */ + ejsDefineCMethod(ejs, httpClass, "fetch", fetchProc, 0); + ejsDefineCMethod(ejs, httpClass, "stop", stopProc, 0); + ejsDefineCMethod(ejs, httpClass, "setCallback", setCallback, 0); + +#if FUTURE + ejsDefineCMethod(ejs, httpClass, "put", put, 0); + ejsDefineCMethod(ejs, httpClass, "upload", upload, 0); + ejsDefineCMethod(ejs, httpClass, "addUploadFile", addUploadFile, 0); + ejsDefineCMethod(ejs, httpClass, "addPostData", addPostData, 0); + ejsDefineCMethod(ejs, httpClass, "setUserPassword", setUserPassword, 0); + ejsDefineCMethod(ejs, httpClass, "addCookie", addCookie, 0); +#endif + + /* + * Define properties + */ + ejsSetPropertyToString(ejs, httpClass, "status", "inactive"); + + /* This default should come from player.xml */ + + ejsSetPropertyToInteger(ejs, httpClass, "timeout", 30 * 1000); + ejsSetPropertyToInteger(ejs, httpClass, "responseCode", 0); + + return ejsObjHasErrors(httpClass) ? MPR_ERR_CANT_INITIALIZE: 0; +} + +/******************************************************************************/ + +void ejsTermHTTPClass(Ejs *ejs) +{ + IWeb *web; + int rc; + + web = (IWeb*) mprGetKeyValue(ejs, "bpWeb"); + if (web) { + rc = IWEB_Release(web); + mprAssert(rc == 0); + } +} + +#endif +/******************************************************************************/ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim:tw=78 + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ -- cgit