Closed
Bug 55594
Opened 24 years ago
Closed 19 years ago
SSJS Request Object problem
Categories
(Core :: JavaScript Engine, defect, P3)
Tracking
()
RESOLVED
WONTFIX
People
(Reporter: naomin, Unassigned)
Details
Request object is not accessable from a user defined method in iWS4.0 (in conjunction with JavaScript14) but works fine in NES3.x (in conjunction with JavaScript12). When trying to access the request object this way, it returns "JSError: Request has no properties". Here is a test application that demonstrates the problem. If you try running it on NES3.x it works fine, on iWS4.x it doesn't work. Download WebServer 4.x. Enable ServerSide JavaScript. Create an SSJS application as follows : initial.html ------------ <SERVER> project.log = new logger; </SERVER> index.html ---------- <HTML> <BODY> <FORM NAME="test4" ACTION="test4.html" METHOD=POST> <B>Attribute:</B> <INPUT TYPE="TEXT" NAME="Attribute" VALUE="" SIZE=40 MAXLENGTH=40> <BR> <INPUT TYPE="SUBMIT" NAME="test" VALUE="Go Test"> </FORM> </BODY> </HTML> functions.js ------------ function writeit() { write('IP Address of user is: ' + request.ip + '<BR><BR>\n'); } function logger() { this.foo = 'abc'; this.callit = writeit; } test4.html ---------- <HTML> <HEAD> <TITLE>Request Object Test</TITLE> </HEAD> <BODY> <SERVER> project.log.callit(); write('Form attribute is: ' + request.Attribute+ '\n'); </SERVER> </BODY> </HTML> jsa.conf ----- test4 uri="/test4" object="/..../test4.web" home="index.html" start="initial.html" client-mode=client-cookie maxdbconnect=1 Run "test4" application. In debug mode, the following is printed : Request for address: test4.html Creating request object: Attribute = "Hello" test = "Go Test" ip = "192.18.176.73" protocol = "HTTP/1.0" method = "POST" agent = "Mozilla/4.7 [en] (X11; U; SunOS 5.6 sun4u)" uri = "/test4/test4.html" Creating client object: Initial project object: log = "[object Object]" Initial server object: hostname = "striper.red.iplanet.com:8889" host = "striper.red.iplanet.com" protocol = "http:" port = "8889" httpdlwVersion = "4.1 Solaris" jsVersion = "4.1 Solaris" Serving page... Error in JavaScript:JSError: services: request has no properties, filename = functions.js, lineno = 0 Final request object: Attribute = "Hello" test = "Go Test" ip = "192.18.176.73" protocol = "HTTP/1.0" method = "POST" agent = "Mozilla/4.7 [en] (X11; U; SunOS 5.6 sun4u)" uri = "/test4/test4.html" Final client object: Final project object: log = "[object Object]" Final server object: hostname = "striper.red.iplanet.com:8889" host = "striper.red.iplanet.com" protocol = "http:" port = "8889" httpdlwVersion = "4.1 Solaris" jsVersion = "4.1 Solaris" ----------------------------------------------------------- At application level , in Debug mode all information is displayed correctly such as Attribute, ip , test ... The debugger shows all correct info. Nothing can be found wrong at this level. At JavaScript engine level, in the user-defined function's scope. There is something I can not explain. lvalue popped from the stack is a negative number (v = -2147483647). This value is passed to js_ValueToObject and evaluated as NULL or VOID, therefore obj becomes NULL object which indicates "not found property". Actually, none of the properties can be found at the function level. WebServer group really needs cooperation from JS engine group whose in-depth knowledge in the JS engine may find the cause of this problem.
Comment 1•24 years ago
|
||
Naomi, is this problem still happening? In order for js_ValueToObject() to return an object, the lvalue passed into it will be a pointer. So the decimal representation of lvalue above could be negative, depending on whether its highest-order bit is set or not. Would you be able to provide a call stack? That will help us track the problem down. Thanks -
Reporter | ||
Comment 2•24 years ago
|
||
Philip, I put a breakpoint in js_ValueToNonNullObject, got the following stack : =>[1] js_ValueToNonNullObject(cx = 0xd3f568, v = -2147483647), line 2493 in "jsobj.c" [2] js_Interpret(cx = 0xd3f568, result = 0xe9142c9c), line 2172 in "jsinterp.c" [3] js_Invoke(cx = 0xd3f568, argc = 1U, constructing = 0), line 670 in "jsinterp.c" [4] js_Interpret(cx = 0xd3f568, result = 0xe9143228), line 2216 in "jsinterp.c" [5] js_Execute(cx = 0xd3f568, chain = 0xd45470, script = 0xb43ee8, fun = (nil), down = (nil), debugging = 0, result = 0xe9143228), line 829 in "jsinterp.c" [6] JS_ExecuteScript(cx = 0xd3f568, obj = 0xd45470, script = 0xb43ee8, rval = 0xe9143228), line 2527 in "jsapi.c" [7] NSR_Context::executeScript(this = 0xd3f538, script = 0xb43ee8, jglobal = 0xa4c3a8, rval = 0xe9143228), line 211 in "context.cpp" [8] NSR_AE_executeScript(p_ctxt = 0xd3f538, pof = 0xb37ee0, scriptInterface = 0xd3f0dc, jscript = 0xb43ee8, jglobal = 0xa4c3a8), line 738 in "appenv.cpp" [9] livewireService(pb = 0x1fe050, sn = 0xb372b4, rq = 0xb372ec), line 1603 in "nsapi.cpp" [10] func_native_pool_wait_work(fn = 0xed7547b8 = &livewireService, poolID = 0, pb = 0x1fe050, sn = 0xb372b4, rq = 0xb372ec), line 549 in "func.cpp" [11] func_exec_str(f = 0x544f08, pb = 0x1fe050, sn = 0xb372b4, rq = 0xb372ec), line 213 in "func.cpp" [12] INTobject_execute(inst = 0x1fd8f8, sn = 0xb372b4, rq = 0xb372ec), line 777 in "func.cpp" [13] _perform_service(sn = 0xb372b4, rq = 0xb372ec, obj = 0x1fd898), line 796 in "httpact.cpp" [14] INTservact_service(sn = 0xb372b4, rq = 0xb372ec), line 822 in "httpact.cpp" [15] INTservact_handle_processed(sn = 0xb372b4, rq = 0xb372ec), line 1314 in "httpact.cpp" [16] HttpRequest::UnacceleratedRespond(this = 0xb37200, pzRequestLine = 0xb709a8 "POST /test4/test4.html HTTP/1.0", pzHost = 0xb709e0 "striper:8889", pzAbsPath = 0xb709c8 "/test4/test4.html"), line 1549 in "httprequest.cpp" [17] HttpRequest::HandleRequest(this = 0xb37200, buf = 0xb6e8b0), line 812 in "httprequest.cpp" [18] DaemonSession::Respond(this = 0xb370c0), line 643 in "daemonsession.cpp" [19] DaemonSession::ThreadMain(this = 0xb370c0), line 576 in "daemonsession.cpp" [20] CThreadMain(vDaemonSession = 0xb370c0), line 264 in "daemonsession.cpp" dbx: warning: can't find file "/u/wtc/release/v3.5.1-19991110/sol26/dbg/ns/nspr20/pr/src/pthreads/ptthread.c" dbx: warning: see `help pathmap' [21] _pt_root(arg = 0xb4c630), at 0xef180614 I printed cx and its components: (/tools/ns/workshop/bin/dbx) p *cx *cx = { links = { next = 0x9db8e8 prev = 0xd089a8 } interpLevel = 2U version = JSVERSION_DEFAULT jsop_eq = '\022' jsop_ne = '\023' runtime = 0x9db7b8 stackPool = { first = { next = 0xd7cd38 base = 13890960U limit = 13890960U avail = 13890960U } current = 0xd7cd38 arenasize = 8192U mask = 3U } fp = 0xe9142cac codePool = { first = { next = (nil) base = 13890992U limit = 13890992U avail = 13890992U } current = 0xd3f5a0 arenasize = 1024U mask = 0 } tempPool = { first = { next = (nil) base = 13891024U limit = 13891024U avail = 13891024U } current = 0xd3f5bc arenasize = 1024U mask = 7U } globalObject = 0xd45470 newborn = (0xd45508, 0xd454e8, (nil), (nil)) regExpStatics = { input = (nil) multiline = 0 parenCount = 0 moreLength = 0 parens = ( { length = 0 chars = (nil) }{ length = 0 chars = (nil) }{ length = 0 chars = (nil) }{ length = 0 chars = (nil) }{ length = 0 chars = (nil) }{ length = 0 chars = (nil) }{ length = 0 chars = (nil) }{ length = 0 chars = (nil) }{ length = 0 chars = (nil) } ) moreParens = (nil) lastMatch = { length = 0 chars = 0xed5f5d98 } lastParen = { length = 0 chars = 0xed5f5d98 } leftContext = { length = 0 chars = 0xed5f5d98 } rightContext = { length = 0 chars = 0xed5f5d98 } } sharpObjectMap = { depth = 0 sharpgen = 0 table = (nil) } argumentFormatMap = (nil) lastMessage = (nil) tracefp = (nil) branchCallback = 0xed75e258 = &ScriptJSBranchCallBack() errorReporter = 0xed75ea28 = &ScriptJSErrorReporter() data = (nil) dormantFrameChain = (nil) gcDisabled = 0 thread = 11847216 requestDepth = 1 gcActive = '\0' throwing = '\0' exception = 0 } (/tools/ns/workshop/bin/dbx) p *(JSClass *)(cx->fp->scopeChain->slots[2]-1) *(struct JSClass *) (cx->fp->scopeChain->slots[2]-1) = { name = 0xed5f3330 "Function" flags = 5U addProperty = 0xed51f7b8 = &JS_PropertyStub(struct JSContext *cx, struct JSObject *obj, jsval id, jsval *vp) delProperty = 0xed5590f8 = &fun_delProperty() getProperty = 0xed559220 = &fun_getProperty() setProperty = 0xed559a28 = &fun_setProperty() enumerate = 0xed5597c0 = &fun_enumProperty() resolve = 0xed559d60 = &fun_resolve() convert = 0xed55a1b0 = &fun_convert() finalize = 0xed55a290 = &fun_finalize() getObjectOps = (nil) checkAccess = (nil) call = (nil) construct = (nil) xdrObject = 0xed55a3c8 = &fun_xdrObject() hasInstance = 0xed55aea0 = &fun_hasInstance() spare = (0, 0) } (/tools/ns/workshop/bin/dbx)p *(JSFunction*)(cx->fp->scopeChain->slots[3]-1) *(struct JSFunction *) (cx->fp->scopeChain->slots[3]-1) = { nrefs = 2 object = 0xa4c4f8 call = (nil) nargs = 0 extra = 0 nvars = 0 flags = '\0' spare = '\0' atom = 0xb2c8b8 script = 0xb246c8 clasp = (nil) } Note that chars in atom is displayed "writeit" which is the name of the user-defined function in which the request is made. (/tools/ns/workshop/bin/dbx)p *(JSClass*)(((JSObject*)cx->fp->scopeChain->slots[1])->slots[2]-1) *(struct JSClass *) (((struct JSObject *) cx->fp->scopeChain->slots[1])->slots[2]-1) = { name = 0xed79920c "global" flags = 0 addProperty = 0xed51f7b8 = &JS_PropertyStub(struct JSContext *cx, struct JSObject *obj, jsval id, jsval *vp) delProperty = 0xed51f7b8 = &JS_PropertyStub(struct JSContext *cx, struct JSObject *obj, jsval id, jsval *vp) getProperty = 0xed51f7b8 = &JS_PropertyStub(struct JSContext *cx, struct JSObject *obj, jsval id, jsval *vp) setProperty = 0xed51f7b8 = &JS_PropertyStub(struct JSContext *cx, struct JSObject *obj, jsval id, jsval *vp) enumerate = 0xed51f828 = &JS_EnumerateStub(struct JSContext *cx, struct JSObject *obj) resolve = 0xed771cb8 = &req_resolve(struct JSContext *cx, struct JSObject *obj, long id) convert = 0xed51f8f8 = &JS_ConvertStub(struct JSContext *cx, struct JSObject *obj, JSType type, jsval *vp) finalize = 0xed51f998 = &JS_FinalizeStub(struct JSContext *cx, struct JSObject *obj) getObjectOps = (nil) checkAccess = (nil) call = (nil) construct = (nil) xdrObject = (nil) hasInstance = (nil) spare = (0, 0) } Let me know if you need more info.
Comment 3•24 years ago
|
||
cc'ing jband, mccabe. John, here is a stack trace of the bug we were discussing yesterday. Can we see what's wrong from this? Why is it that the parameter "v" at the top of the stack has a decimal representation, when all the other parameters are in hex? Also note Naomi's comment, "Note that chars in atom is displayed "writeit" which is the name of the user-defined function in which the request is made."
Comment 4•24 years ago
|
||
-2147483647 is just the decimal representation of 0x80000001. This is the value of the constant JSVAL_VOID (see the top of jsapi.h). It looks like jsval is ultimately typedef'd to long and that particular debugger decides to print that type as signed decimal. This is not the problem. The problem is that request is just not found in the scope when this function is invoked. naomin, Is there any other reason to think that this is a core JS engine problem? I can't see why this JS code *should* work. If you pass request into writeit/callit then it should work fine. But, I don't see how you could expect the request object to be in the static scope of the writeit function which is attached to the project object. Unless ssjs is doing something really odd, it seems to me, that this function is created in the scope of whatever global is current when initial.html is run. That selfsame global object doesn't get a 'request' object mapped in as a property when you later receive a request does it?
Reporter | ||
Comment 5•24 years ago
|
||
js_ValueToNonNullObject(JSContext *cx, jsval v) { JSObject *obj; JSString *str; if (!js_ValueToObject(cx, v, &obj)) return NULL; if (!obj) { str = js_DecompileValueGenerator(cx, v, NULL); if (str) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_PROPERTIES, JS_GetStringBytes(str)); } } return obj; } v has the value of 0x80000001. It was passed in the call to js_ValueToObject : JSBool js_ValueToObject(JSContext *cx, jsval v, JSObject **objp) { JSObject *obj; if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) { obj = NULL; } else if (JSVAL_IS_OBJECT(v)) { obj = JSVAL_TO_OBJECT(v); if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_OBJECT, &v)) return JS_FALSE; if (JSVAL_IS_OBJECT(v)) obj = JSVAL_TO_OBJECT(v); } else { if (JSVAL_IS_STRING(v)) { obj = js_StringToObject(cx, JSVAL_TO_STRING(v)); } else if (JSVAL_IS_INT(v)) { obj = js_NumberToObject(cx, (jsdouble)JSVAL_TO_INT(v)); } else if (JSVAL_IS_DOUBLE(v)) { obj = js_NumberToObject(cx, *JSVAL_TO_DOUBLE(v)); } else { JS_ASSERT(JSVAL_IS_BOOLEAN(v)); obj = js_BooleanToObject(cx, JSVAL_TO_BOOLEAN(v)); } if (!obj) return JS_FALSE; } *objp = obj; return JS_TRUE; } objp is null and JS_TRUE is returned to js_ValueToNonNullObject. Since obj is null, the following code is executed : if (!obj) { str = js_DecompileValueGenerator(cx, v, NULL); if (str) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_PROPERTIES, JS_GetStringBytes(str)); } } js_DecompileValueGenerator returns a name "request". And then JS_ReportErrorNumber is called to report the error. Look like js_DecompileValueGenerator can't find the request. I don't know at detail level how this function does it. Note that Nescape Enterprise Server 3.6 works using the same test case. NES3.6 uses JavaScript 1.2 or some version earlier than JavaScript 1.4. I don't blame core JS code completely. The problem may come from both sides. That is why I need your expertise in JS code to analyze the cause. A couple weeks ago, I provided a work-around to customers: request should be passed to project.log.callit(request) and put request in the function parameter of function writeit. The testcase has worked in NES3.6. What makes it fail on NES 4.x ? I have looked at SSJS application layer and found nothing suspicous.
Comment 6•24 years ago
|
||
I asked Brendan about why ssjs could have ever succeeded with this kind of lookup that didn't follow the static scoping rules. He said that older versions of ssjs likely used the old (and removed) JSFUN_GLOBAL_PARENT flag: #define JSFUN_GLOBAL_PARENT 0x80 /* reparent calls to cx->globalObject */ Assuming that this behavior is truly required, then whoever adapted ssjs to use a newer JS engine should have worked around this in some way that would emulate the old behavior for user scripts. naomin, do you know if there are likely to be many real world scripts that will break? Were you heavily involved with the conversion of ssjs to use the newer engine? If not, is there anyone still around who you might ask about details of that conversion? Can you look at the code change history and see what kind of changes accompanied the (presumed) removal of the used of JSFUN_GLOBAL_PARENT? Brendan had some suggestions for how one might do that. Perhaps he'll add them here...
Status: UNCONFIRMED → NEW
Ever confirmed: true
Reporter | ||
Comment 7•24 years ago
|
||
John, I was not involved in the conversion of ssjs to accomodate the newer JS. I have been with the company for less than a year! All the SSJS folks are gone. Looking at the history of SSJS changes, vishy is the one that ported JS1.4 to NES4.0. I will contact him about this issue. Hopefully, he still remembers what he did almost two years ago. At the same time, if your group have any suggestion how to deal with this, please let me know. Thanks !
Comment 8•24 years ago
|
||
JS1.4 supported JSFUN_GLOBAL_PARENT, IIRC. Anyway that's not a supported engine rev, AFAIK. Reassigning to beard. /be
Assignee: rogerl → beard
Reporter | ||
Comment 9•24 years ago
|
||
Sorry, what are IIRC and AFAIK ?
Comment 10•24 years ago
|
||
IIRC = If I Recall Correctly AFAIK = As Far As I Know Sorry about geeking out there! /be
Comment 11•24 years ago
|
||
Why isn't the workaround "request should be passed to project.log.callit(request)" sufficient? If it isn't, then I'd guess you need to define the request object in a more global scope, so it is seen by the code called from test4.html. What isn't clear to me, is the JavaScript code in the SERVER element wrapped in its own function, which is passed request as an, or is it evaluated at top-level? If it is evaluated at top-level, then request would seem to be a global variable already, and then would be visible to the writeit. Dynamic scoping has fallen into disrepute over the years. Passing the request as an explicit parameter is a MUCH better idea, and leads to much more maintainable code.
Comment 12•24 years ago
|
||
beard: the JSFUN_GLOBAL_PARENT hack was a limited form of dynamic scoping that looked like static scoping in the SSJS environment. It allowed functions to be compiled once, offline, and their bytecodes loaded and functions adopted by a "superglobal". When called, these functions were reparented to the running cx's globalObject. No one was the wiser, because different server threads cannot see one anothers request objects (which are the threads' contexts' globalObjects, if that makes sense). I don't know who broke things in this case, which has nothing to do with any Mozilla code. I think this bug shouldn't even be in bugzilla, but it's not the worst offense in that regard. SSJS folks, please grep for JSFUN_GLOBAL_PARENT in all sources (SSJS and your JS1.4 snapshot). /be
Comment 13•24 years ago
|
||
When a future SSJS implementation migrates to JS 1.5, a workaround for this will have to be developed. Changing milestone to Future.
Status: NEW → ASSIGNED
Target Milestone: --- → Future
Updated•19 years ago
|
Assignee: beard → general
Status: ASSIGNED → NEW
QA Contact: pschwartau → general
Target Milestone: Future → ---
Updated•19 years ago
|
Status: NEW → RESOLVED
Closed: 19 years ago
Resolution: --- → WONTFIX
You need to log in
before you can comment on or make changes to this bug.
Description
•