+ Reply to Thread
Page 1 of 2 1 2 LastLast
Results 1 to 10 of 16

Thread: blockAndCallUrl() mangles data

  1. #1
    Junior Member
    Join Date
    Dec 2010
    Posts
    18
    Thanks
    5
    Thanked 1 Time in 1 Post

    blockAndCallUrl() mangles data

    I'm using res = getApi().blockAndCallUrl(...) in an ActionScript login event handler. When res.getDataAsString() is executed, the string is a somewhat mangled version of what is sent across the wire. URL is a normal "http://" one, data is fine in other situations, method is GET.

    What happens looks like a buffer overwrite error: parts of the string are repeated towards the end.

    Is there a limit to the length of the content? What I'm reading is never bigger than a few K in size.

  2. #2
    Administrator tcarr's Avatar
    Join Date
    Dec 2007
    Posts
    7,219
    Thanks
    80
    Thanked 1,087 Times in 1,076 Posts
    I *think* ActionScript requires using callUrlFromScript (not positive on this). The other two methods are only for use from Java methods. You also don't want to do something as time consuming as calling a url from inside a login event handler in most cases - a more scalable solution is to just log the user in with guest status, then the user's client sends a plugin request to a server level plugin which does the database or url call. the result of the call would then either change the user's status to member or whatever, or else kick him off the server.
    Teresa Carrigan
    Senior Engineer
    Electrotank, Inc.

  3. #3
    Junior Member
    Join Date
    Dec 2010
    Posts
    18
    Thanks
    5
    Thanked 1 Time in 1 Post
    Thanks, I expected it was something like that. The requests are very lightweight, so response times aren't a problem in this case, and the server queried also resides on 127.0.0.1, but later asynchronous calls would be used. At the moment I'm just prototyping things, so blocking I/O and ActionScript are ok. What's the best way of delaying execution using ES? Scheduled callbacks?

  4. #4
    Administrator tcarr's Avatar
    Join Date
    Dec 2007
    Posts
    7,219
    Thanks
    80
    Thanked 1,087 Times in 1,076 Posts
    Scheduled callback is usually the best way to delay execution. If I need to do something a second or two later, during a LoginEventHandler, what I would do is keep a BlockingQueue structure to hold objects consisting of usernames and timestamps, then a single repeating scheduled callback that runs every 500ms or 1000ms or something, and drains the BlockingQueue of any elements that have stale enough timestamps on them. That's possible to do from AS1 but awkward. For low numbers of ccu, separate scheduled callbacks would work inside a LoginEventHandler but I sure wouldn't want to try that on a production server. Separate scheduled callbacks are probably fine from a server level plugin, but I'd check when I tried to restart the ES5 to make sure that it actually shut down properly, or else maintain a concurrent data structure of some type with the pending scheduled callbacks, and in the destroy method cancel all of them.
    Teresa Carrigan
    Senior Engineer
    Electrotank, Inc.

  5. #5
    Junior Member
    Join Date
    Dec 2010
    Posts
    18
    Thanks
    5
    Thanked 1 Time in 1 Post
    In production, everything would be async, nonblocking and not polled. Perhaps it's easiest, after all, to use a two-stage login process. With ES, it seems easiest to set up User Vars after the user has logged in. Unless creating User Vars on the login context structure somehow makes them appear automatically on the user after a successful login?

  6. #6
    Administrator tcarr's Avatar
    Join Date
    Dec 2007
    Posts
    7,219
    Thanks
    80
    Thanked 1,087 Times in 1,076 Posts
    You can't create user vars during login using the normal method. Try LoginContext.addUserVariable. I don't recall whether the client notices a user variable added that way, but you could certainly make a UserVariableEventHandler which would send a plugin message to the user saying "hey your user var has been created!".

    The two step login process is recommended if login is complicated, because it scales better. That is, if you plan on eventually needing to process hundreds of logins a second, and need a database lookup during the login, the use the two step method. If you are unlikely to ever have more than 1000 ccu, then you probably don't need to bother.
    Teresa Carrigan
    Senior Engineer
    Electrotank, Inc.

  7. #7
    Junior Member
    Join Date
    Dec 2010
    Posts
    18
    Thanks
    5
    Thanked 1 Time in 1 Post
    The docs seem to suggest that there is a mirroring of LoginContext.addThisThatOrTheOther to the user. I'll experiment and see.

    By the way, I tried using callUrlFromScript(), but the same thing happens: the body of the HTTP response shows the same signs of buffer overwrite as the synchronous version. Is there some additional configuration required that I'm missing?

  8. #8
    Administrator tcarr's Avatar
    Join Date
    Dec 2007
    Posts
    7,219
    Thanks
    80
    Thanked 1,087 Times in 1,076 Posts
    I'll add that one as a bug report to our system and see if we can reproduce it.
    Teresa Carrigan
    Senior Engineer
    Electrotank, Inc.

  9. The Following User Says Thank You to tcarr For This Useful Post:

    PeterB (01-02-2011)

  10. #9
    Junior Member
    Join Date
    Dec 2010
    Posts
    18
    Thanks
    5
    Thanked 1 Time in 1 Post
    Here's the shortest reproducible example. The content-type is application/json. This is sent (including newlines):

    {"total_rows":3,"offset":2,"rows":[
    {"id":"5","key":"uname","value":1}
    ]}

    and here's what's received:

    {"total_rows":3,"offset":2,"rows":[
    {"id":"5","key":"uname","value":1}
    ]}
    :[
    {"id":"5","key":"uname","value":1}

  11. The Following User Says Thank You to PeterB For This Useful Post:

    tcarr (01-03-2011)

  12. #10
    Junior Member
    Join Date
    Dec 2010
    Posts
    18
    Thanks
    5
    Thanked 1 Time in 1 Post
    A little further experimentation shows that getDataAsString() returns a string of length 3072. What is sent via HTTP is correct. When logging the string it is nowhere near that length. Trying to shorten the string heuristically by seaching for "\n]}\n", given the string above, returns an index of 2049. Truncating the string at that index gives something that looks OK in the log, but which when parsed returns an error at index 1067.

    I might be missing something Java-specific here (I'm not a Java guy). Enclosing the relevant log lines and the ActionScript JSON conversion function.

    ----------------------------------
    16:22:42,087 [pool-1-thread-4] DEBUG Extensions.HorizonLogin.EventHandlers.HorizonLogin - About to parse: {"total_rows":3,"offset":2,"rows":[
    {"id":"5","key":"abcde","value":1}
    ]}
    :[
    {"id":"5","key":"abcde","value":1}
    16:22:42,166 [pool-1-thread-4] DEBUG Extensions.HorizonLogin.EventHandlers.HorizonLogin - Length: 3072
    16:22:42,166 [pool-1-thread-4] DEBUG Extensions.HorizonLogin.EventHandlers.HorizonLogin - End sequence found at 2049
    16:22:42,166 [pool-1-thread-4] DEBUG Extensions.HorizonLogin.EventHandlers.HorizonLogin - Reduced to: {"total_rows":3,"offset":2,"rows":[
    {"id":"5","key":"abcde","value":1}
    ]}

    16:22:42,167 [pool-1-thread-4] DEBUG Extensions.HorizonLogin.EventHandlers.HorizonLogin - Length: 2053
    16:22:42,223 [pool-1-thread-4] ERROR com.electrotank.electroserver5.entities.ActionScri ptLoginEventHandlerEngine - Error while invoking callback method 'httpRequestComplete'
    javax.script.ScriptException: sun.org.mozilla.javascript.internal.WrappedExcepti on: Wrapped Unexpected character () at position 1067. (<Unknown source>#80) in <Unknown source> at line number 80
    at com.sun.script.javascript.RhinoScriptEngine.invoke (RhinoScriptEngine.java:184)
    at com.sun.script.javascript.RhinoScriptEngine.invoke Function(RhinoScriptEngine.java:142)
    at com.electrotank.electroserver5.entities.ActionScri ptLoginEventHandlerEngine.invokeCallbackMethod(Act ionScriptLoginEventHandlerEngine.java:101)
    at com.electrotank.electroserver5.entities.LoginEvent HandlerBridge$2.call(LoginEventHandlerBridge.java: 45)
    at com.electrotank.electroserver5.entities.BaseBridge .withLockAndClassloader(BaseBridge.java:198)
    at com.electrotank.electroserver5.entities.BaseEventH andlerBridge.withLockAndClassloader(BaseEventHandl erBridge.java:80)
    at com.electrotank.electroserver5.entities.LoginEvent HandlerBridge.invokeCallbackMethod(LoginEventHandl erBridge.java:43)
    at com.electrotank.electroserver5.entities.ScriptHttp Callback.httpCallback(ScriptHttpCallback.java:18)
    at com.electrotank.electroserver5.entities.BaseBridge $1.call(BaseBridge.java:101)
    at com.electrotank.electroserver5.entities.BaseBridge .withLockAndClassloader(BaseBridge.java:198)
    at com.electrotank.electroserver5.entities.BaseBridge .executeHttpCallback(BaseBridge.java:99)
    at com.electrotank.electroserver5.extensions.api.Elec troServerApiImpl$1.run(ElectroServerApiImpl.java:1 130)
    at java.util.concurrent.Executors$RunnableAdapter.cal l(Executors.java:441)
    at java.util.concurrent.FutureTask$Sync.innerRun(Futu reTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.jav a:138)
    at java.util.concurrent.ScheduledThreadPoolExecutor$S cheduledFutureTask.access$301(ScheduledThreadPoolE xecutor.java:98)
    at java.util.concurrent.ScheduledThreadPoolExecutor$S cheduledFutureTask.run(ScheduledThreadPoolExecutor .java:206)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run Task(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)

    ------------------------

    importPackage(org.json.simple);
    importPackage(org.json.simple.parser);

    function parseJSON(jsonText) {
    jsonText = jsonText.toString();
    trace("About to parse: " + jsonText);
    trace("Length: " + jsonText.length());
    // Reduce it heuristically
    var i = jsonText.indexOf("\n]}\n");
    trace("End sequence found at " + i.toString());
    jsonText = jsonText.substring(0, i+4);
    trace("Reduced to: " + jsonText);
    trace("Length: " + jsonText.length());
    // Parse it using JSONSimple
    var obj = null;
    var parser = new JSONParser();
    obj = parser.parse(jsonText); // This is the line that throws the exception
    trace("Parse successful: " + obj.toString());
    }

+ Reply to Thread

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts