Pliant talk forum

Pliant talk forum

Discussion: http_proxy.pli

A place to put & discuss all hacks for http proxy
Message posted by maybe Boris Reitman on 2007/11/25 08:49:38
I will keep my latest version here,
Message posted by maybe Hubert Tonneau on 2007/11/25 11:50:59
We have to find the explaination of why we get 'Session if closed' rather than
just hide the message in the status bar.

Here are the other minor remarks;
. I don't like the 'Expire' in the no_cache constant
. Your handling of character 3 (jump to another URL) needs to be better written
  Let's remove handling of character 3 and 4 ouside of the while loop and
  handle them the same way character 4 is already handled within the loop
. custom_startup does not exist
Message posted by maybe Boris Reitman on 2007/11/26 09:07:42

About Cache-Control header. I have seen recommendation to set Expire: header to 0 or -1.
But it doesn't matter.  In all cases I can't get correct behaviour.  I want to have the page
reload if user presses "Back" button to get back to a previously seen pliant page.
If no reload occurs, the state of the page is reset on the server, but not on the client.
Looks like this needs to be detected in startup() because onload is re-executed for 
cached pages too.

The custom_startup() function must be provided by the user code. The if (custom_startup)
safely skips if such function is not provided. So I don't see the problem with that.

About the REDIRECT stuff I agree.

About "Session is closed". A better way would be to overlay a div on top of the page,
instead of the alert() or status. Because if user has several windows open, and the message pops out
when he is doing something else, he will not know to which window it refers.
The div will say: 
"Connection to server is paused. 
 Please refresh the page or press "Reconnect" button below to reconnect to the server."

About smart cursor. The way it works now, if connection is lost, it can get stuck
in wait state. Thats very confusing, so I need to add a timer that will reset it
back to normal state after timeout. Without the wait cursor, user experience
is confusing over slow connection.
Message posted by maybe Boris Reitman on 2007/11/26 22:10:32
Here's an example for modal dialog to use instead of alert():
Message posted by maybe Hubert Tonneau on 2007/11/26 23:25:35
It's much better, but does not solve the main issue which is:
why do we get session is closed from time to timer ?
Message posted by maybe Boris Reitman on 2007/11/27 10:55:37
I have made changes to allow custom alert code, + I have fixed advanced_cursor.
I have added the wait icon not only on button but also on change request.

The patch:

The full file:

External code for the custom alert:

That code still needs work to grey out the whole document and to work 
on both IE and Firefox. Right now it greys out only the top visible part of 
the window.

It would probably be more appropriate to show wait cursor only for blocks on which
"hook" is registered, because only in those cases user will expect to see a change
in the UI after the wait.
Message posted by maybe Boris Reitman on 2007/11/28 16:46:50
I have updated the modal dialog code to a better one.
Also, I have changed http_proxy.pli to use strict-mode DOCTYPE: 

Message posted by maybe Boris Reitman on 2007/11/30 14:04:00
I found that it works much better to popup the modal box after a delay of 
2 to 4 seconds. 

This is because when when a user clicks a link on a page 
right during alive request, the server invokes the ajax callback which will 
report that connection to pliant server is lost. Instead, if the popup is 
registered with a delay, when user completely leaves the current page, 
the browser will delete all pending actions on the old page, including the 
popup message.

I have updated my code:
Message posted by maybe Hubert Tonneau on 2007/11/30 21:51:03
Great. That might be the explaination.

I also have good news on the stability front:

I've discovered that the glibc malloc interface used by several libraries is
not thread safe when called from Pliant.
I've installed hooks and verified it through intensive multithreaded use of
libjpeg on a 4 cores processor.
It might solve some of your strange problems when interfacing Perl.

I have also discovered that during the 2.6 Linux kernel evolution, they switched
the way mmap handles the address space, with an unwanted side effect of a
greatly reduced threads scalibility for Pliant.
I've also written a work around for that.

And I've also found a bug related to thread headers creation/destruction.

I'll publish a new release of Pliant with all of this this week end.
Message posted by maybe Boris Reitman on 2007/12/02 12:27:21
That's great. I don't know how to do that, and I should learn about 
hooks like those to enable be to debug such problems.

I have updated again http_proxy.pli with two boolean switches: shrinkwrap_input
and shrinkwrap_textarea.  Website users are not used to growing text input boxes,
so a commercial website must not use a surprising interface. Same url:

Perhaps a better approach for binding events to input fields is to give 
each input field a unique id, and bind events to it from an external block
in startup().  We need unique ids for inputfields anyway, 
to allow automated testing of the ui.
Message posted by maybe Hubert Tonneau on 2007/12/02 14:25:32
Release 100 contains important fixes that might provide the answer to some of
the problems you have reported.
It also contains a rewrite of character 3 and 4 special handling in the HTTP
The error report was also buggy when the error was raising not in the main
thread of the process.
Please check what is solved or not for you, then post a new summary of the
Message posted by maybe Boris Reitman on 2007/12/23 14:39:19
I tried including a pliant-based website inside an iframe, and I got this error,
uncaught exception: Permission denied to get property Window.innerWidth
Message posted by maybe Boris Reitman on 2007/12/24 14:09:08
I have merged previous changes at release 100 with http_proxy.pli of mine.

I am having trouble with your implementation of url redirect, because I don't know
how to call it from ui page.  url_call "http://..." and url_call "http://..." didn't
work for me. If I continue with html "REDIRECT:http://..." then I need to use 
an dummy section, because without a wrapper section "html" can't be used 
(everything crashes).

Therefore, I have factored the code into a custom plugin called "apply".
I have also added support for arbitrary Javascript code to be evaled on the client
(delimited by character:5).

Note: With the 'wait' handling it is important to set the 'wait' state before call 
to ajax send(), not after.

Another todo: inside an input text field, Enter key in IE doesn't run change().
It works ok on firefox.

I think we need a version control system with http_proxy.pli. Maybe 
we should use svn for it.
Message posted by maybe Hubert Tonneau on 2007/12/24 16:12:41
I'm very conservative at the moment with the HTTP proxy code because the
HTTP proxy is still not stable enough according to my personal quality taste.

So, what I plan to do is deal mostly with bug fixes until I reach decent
stability, again, according to my personal quality standard that are not at
all granted to match others ones.
This must not prevent you to try to add features faster.
I will diff your code from time to time, apply some changes that I find non
intrusive and that bring higher flexibity, add a fiew plugins to enable your
code to be easier to layer on top of mine, but I will not put advanced
features for the moment.
When stability is reached, then it will be time to put advanced features,
test the impact on stability, and reverse if it goes down.

If you set a fixed URL for your HTTP proxy module, I can put a comment at
the beginning of the code to specify where to get the more experimental one.
Message posted by maybe Boris Reitman on 2008/01/24 00:40:21
I will keep the latest code at

I have fixed a bug in http proxy with Enter keypress inside a textbox 
to call change().  It was working fine on Firefox, but not in IE.
To make it work I had to add onKeydown() event for IE textbox,

  if browser_model="ie"
    http writeline "function keydown(f,e) {"
    http writeline "  if (e.keyCode != 13) return;"
    http writeline "  e.cancelBubble = true; e.returnValue = false;"
    http writeline "  change(f);"
    http writeline "  return true;"
    http writeline "}"


    if gather_infos and c:browser_model="ie"
      http writechars "<input type=[dq]text[dq] name=[dq]"+(http_encode i:id)+"[dq] value=[dq]"+(html_encode i:value)+"[dq]"+(shunt shrinkwrap_input " size=[dq]"+string:(max (utf8_decode i:value):len 1)+"[dq] onKeyup=[dq]adjust(this)[dq] onPaste=[dq]paste(this,1)[dq]" "")+" onKeyDown=[dq]return keydown(this, event)[dq] onChange=[dq]change(this)[dq]"

Message posted by maybe Boris Reitman on 2008/02/16 08:58:12
I have updated the code to not use cookies. This allows two browser windows or two firefox tabs to load the same url. It can been seen in live operation at:


This http_proxy version can be downloaded from

Also, I am trying to use "" javascript property to remember the session id. ( persists across urls) This will allow plain, non-pliant links to reuse same session id, and limit number of open connections on server, and reduce memory overhead. So I thought of the following patch,

Except, it doesn't work because I don't know how to do a "cache_move" to rename a key into another key. I get a crash on this line of patch,

+        c:console request_sem s
Any suggestions ? Another way is to modify in javascript all non-pliant links with onClick() method.
Message posted by maybe Boris Reitman on 2008/02/17 09:18:24
I have managed to pass cookie using url_set.  At this point url_set cross still
doesn't work reliably under http_proxy.pli environment, probably because sessions
are dropped. As a workaround, I am passing the cookie on session creation
by population session:session_env before connect_main call.  
I wrote a function url_set_gsid.

#FIXME: need to get this from pml/io.pli
method s write_count code i
  arg_rw Stream s ; arg Int code i
  check i>=0
  if processor_is_low_indian
    var Int n := shunt i<2^8 0 i<2^16 1 Int:size=4 or i<2^32 2 3
    var uInt8 u8 := code+n ; s raw_write addressof:u8 1
    s raw_write addressof:i 2^n
    error "not implemented"
method s to_stream stream
  arg Str s ; arg_rw Stream stream
  if s:len<2^4
    var uInt8 u8 := 10100000b+s:len ; stream raw_write addressof:u8 1
    stream write_count 11101000b s:len
  stream raw_write s:characters s:len

method session url_set_gsid value
  arg_rw UISession session ; arg Str value
  var Pointer:(Dictionary Str Blob) env :> session session_env
  constant name "gsid"
  var Pointer:Blob b :> env first name
  if not exists:b
    var Blob bb
    (var Stream s) open bb out+safe
    value to_stream s
    s close
    env insert name bb


I'm not sure how to access "to stream" from pml/io.pli, I tried several things,
and got error ". to stream" not found every time.  Can you help me clean 
this up ?

I have updated http_proxy.pli on my pliant homepage

and uploaded another demo:


Message posted by maybe Boris Reitman on 2008/04/09 23:47:35
# lazy sessions for website mode:
#       - instead of deleting sessions on timeout, create only on demand.
#       - most sessions are generated by bots, not by human users.
#       - websites have thousands dynamic-generated landing pages for bots to visit
#       - users first get a page "preview". real session is created on javascript action
#       - generated javascript is static, same for all paths and users.
#       - bots will use no more sessions than their number.
#       - number of ui sessions will reflect the number of human users
#       - externally cache pliant website as work-around to http_proxy performance bugs
#       - pliant website can be completely cached with apache mod_cached
#       - ui_threads will be broken if they are supposed to do per-user work on page load.
#       - startup() now receives arguments to identify the page
#       - ajax requests add original ui_path in GET url
#       - active users on load are detected by matching js-generated gsid cookie
#       - ?refresh forces to drop session and reconnect
#       - alive requests don't launch on page load, but after first user action
# cache mode:
#       - homepage / is always fully refreshed (requested by cache engine on page expire)
#       - any other path /x/y/z.html will be auto-reloaded by javascript:
#           - if user already has a cookie sid=javascript_key... do nothing
#           - otherwise set gsid cookie to start with javascript_key, and reload page
#           - or if cookies are disabled, add ?sid= parameter to url and reload
#           - attempt at most 1 reload, keep state inside
#       - caching rules:
#          allow:
#           - user_agent is a known bot
#          deny:
#           - javascript_key appears in cookies
#           - ?sid= or ?refresh appears in url
#           - url starts with url_header /_
#           - referer is google, yahoo or msn search engine
#          otherwise: allow
#       - cache layers can be stacked (apache mod_cache on top of this cache)
Message posted by maybe Boris Reitman on 2008/04/13 23:43:26
# lazy sessions for website mode:
#       - instead of deleting sessions on timeout, create only on demand.
#       - most sessions are generated by bots, not by human users.
#       - websites have thousands dynamically generated landing pages for bots to visit
#       - users first get a page "preview". real session is created on javascript action
#       - generated javascript is static, same for all paths and users.
#       - bots will use no more sessions than their number.
#       - number of ui sessions will reflect the number of human users
#       - externally cache pliant website as work-around to http_proxy performance bugs
#       - pliant website can be completely cached with apache mod_cached
#       - ui_threads will be broken if they are supposed to do per-user work on page load.
#       - startup() now receives arguments to identify the page
#       - ajax requests add original ui_path in GET url
#       - active users on load are detected by matching js-generated gsid cookie
#       - ?refresh forces to drop session and reconnect
#       - alive requests don't launch on page load, but after first user action

# caching:
#       - always serve from cache for non-active users
#       - detect active (human) users if:
#           - active_key appears in cookies
#           - or ?sid= appears in url
#       - auto-reload by javascript to detect active users
#           - set gsid cookie to start with active_key, and reload page
#           - or if cookies are disabled, add ?sid= parameter to url and reload
#           - use to keep state accross reloads
#       - use ?active ?inactive to force a mode.
#       - to update cache use ?refresh with wget (or disable javascript and cookies)
# apache integration (optional):
#       mod_cached: serve from cache unless
#           - active_key appears in cookies
#           - ?sid= or ?refresh or ?active appears in url
#           - url starts with url_header /_
#           - referer is google/yahoo/msn search engine
#       mod_rewrite: append to url
#          ?inactive if user is a known bot
#          ?active if user is human (definitely not a bot)
#          ?active if referer is google/msn/yahoo search engine

Download http_proxy.pli that supports all this changes from:
Message posted by maybe Boris Reitman on 2008/04/22 18:03:06

Homepage for advanced http_proxy:

released version 0.94 of http_proxy. It now applies display:none on sections that are empty. This is needed when sections have padding through css and we want the sections to disappear completely when they have no content.

Message posted by maybe Boris Reitman on 2008/04/30 17:33:07

A preview of whats coming:

I will make a release by next week.

Message posted by maybe Hubert Tonneau on 2008/05/01 13:38:04
Thanks Boris for your contributions, I will start to review.

We have several issues to deal with:
. close threads that are not used for several seconds. Easy.
. when too many clients are connecting at once, instead of the current behaviour
  which is to not accept new ones, a better behaviour would be to discard
  what we compute as less active ones. A bit like Linux kernel OOM killer.
. when a query on the server takes too long, how to we prevent too many of these
  to be requested ?
. special case of the same issue: how do we handle clients waiting for compile
  semaphore ?

The general scenario is:
. a user asks for some URL content
. he does not receive the answer after a fiew seconds
. so he clics on again and again, opening more and more requests to the server

Please notice that the explaination of not receiving the answer can be either
that processing the answer is long, or that the server is currently compiling
on the fly the code of the concerned .ui module

The general question is do we use an automatic congestion system, a manual
one, or a mixture ?

One of the serious constrains about Pliant is: since it's an efficient language,
it is not possible to stop a thread without the help of the stopped thread
(assuming that it is really sane to do it on unefficient ones)
Message posted by maybe Boris Reitman on 2008/05/04 21:03:15
I'm not ready to make a clean release yet, but I have put a tarball for you

You can start reviewing the code there.

Message posted by maybe Boris Reitman on 2008/05/04 22:35:25

I'd like to be able to put CPU limitations on jobs submitted by the user.
In other words, the pliant system is an OS and threads are equivalent to processes
in the old unix systems, where people connected using dump terminals and executed
jobs in the shell.

For example, I have a ui that ask the user for input numbers to a cpu 
time-consuming computation. I want the thread associated with the job to be 
"niced" with a low priority, because I don't want the user to kill my server.

So, maybe we need to add a parameter to the thread construct to specify priority.

Regarding other issues you listed. I have solved my problems temporarily by
splitting the robot traffic and human traffic, and splitting the human traffic
into active and browser (cache) users.  Only active users (users that actually 
clicked on a button) need a working session that doesn't die. bots and inactive 
browser users only need to get a rendered page, and thats it. Their session can 
be closed. 

When user becomes active as a result of pressing some button,
we can show him "Please wait" dialog if connection is taking too long 
to establish (rather than just sand-clock cursor).  Then the user will 
not click insanely again and again.

If you look in the new_session function, I am using a semaphore to make sure 
that session creation is not requested twice.

There is a bug in http_proxy somewhere because memory usage always grows.
Also I have been noticing 100% cpu load, we have some tight-loops in the ui 
client code probably. I haven't debugged that part yet. 

Also, the maximum memory setting for logical computers through the host computer
 didn't propagate somehow,
I had to manually connect to each logical computer and set the memory setting.
Whithout sufficiently large maximum memory setting the cache module was 
closing connections on me.
Message posted by maybe Boris Reitman on 2008/06/02 01:31:52
Just found out today about: 

window.onbeforeunload = function(){ code to end session }

we can use it to close sessions earlier, without relying on alive timeouts.