pike.git / lib / modules / Protocols.pmod / HTTP.pmod / Session.pike

version» Context lines:

pike.git/lib/modules/Protocols.pmod/HTTP.pmod/Session.pike:1:   #pike __REAL_VERSION__    - // $Id: Session.pike,v 1.3 2003/02/21 21:45:04 mirar Exp $ + // $Id: Session.pike,v 1.4 2003/02/22 10:21:18 mirar Exp $      import Protocols.HTTP;      //! The number of redirects to follow, if any.   //! This is the default to the created Request objects.   //!   //! A redirect automatically turns into a GET request,   //! and all header, query, post or put information is dropped.   //!   //! Default is 20 redirects. A negative number will mean infinity.
pike.git/lib/modules/Protocols.pmod/HTTP.pmod/Session.pike:32:   //! the request will perform another request if the   //! HTTP answer is a 3xx redirect.   //! Default from the parent @[Session.follow_redirects].   //!   //! A redirect automatically turns into a GET request,   //! and all header, query, post or put information is dropped.   //! @bugs   //! Loops will currently not be detected, only the limit   //! works to stop loops.    -  int follow_redirects= // parent +  int follow_redirects= // from parent, will count down    function_object(object_program(this_object()))->follow_redirects;      //! Cookie callback. When a request is performed,   //! the result is checked for cookie changes and   //! additions. If a cookie is encountered, this   //! function is called. Default is to call   //! @[set_http_cookie] in the @[Session] object.       function(string,Standards.URI:mixed) cookie_encountered=set_http_cookie;      // ----------------    -  +  int(0..1) con_https; // internal flag +    //! Prepares the HTTP Query object for the connection,   //! and returns the parameters to use with @[do_sync],   //! @[do_async] or @[do_thread].   //!   //! This method will also use cookie information from the   //! parent @[Session], and may reuse connections (keep-alive).       array(string|int|mapping) prepare_method(    string method,    string|Standards.URI url,    void|mapping query_variables,    void|mapping request_headers,    void|string data)    {    if(stringp(url))    url=Standards.URI(url);    url_requested=url;    -  if(!con) con = give_me_connection(url); -  +     if(!request_headers)    request_headers = ([]);    -  +    #if constant(SSL.sslfile)    if(url->scheme!="http" && url->scheme!="https")    error("Protocols.HTTP can't handle %O or any other "    "protocols than HTTP or HTTPS\n",    url->scheme);    -  con->https= (url->scheme=="https")? 1 : 0; +  con_https= (url->scheme=="https")? 1 : 0;   #else    if(url->scheme!="http" )    error("Protocols.HTTP can't handle %O or any other "    "protocol than HTTP\n",    url->scheme);   #endif       if(!request_headers)    request_headers = ([]);    mapping default_headers = ([
pike.git/lib/modules/Protocols.pmod/HTTP.pmod/Session.pike:144:   //! Get arguments from @[prepare_method].   //! @returns   //! 0 upon failure, this object upon success   //! @seealso   //! @[prepare_method], @[do_async], @[do_thread]       Request do_sync(array(string|int|mapping) args)    {    for (;;)    { +  if(!con) con=give_me_connection(url_requested);    con->sync_request(@args);    if (con->ok)    {    check_for_cookies();    if (con->status>=300 && con->status<400 &&    con->headers->location && follow_redirects)    {    Standards.URI loc=    Standards.URI(con->headers->location,url_requested);   
pike.git/lib/modules/Protocols.pmod/HTTP.pmod/Session.pike:177:      // ---------------- thread      //! Start a request in the background, using a thread.   //! Call @[wait] to wait for the thread to finish.   //! Get arguments from @[prepare_method].   //! @returns   //! The called object.   //! @seealso   //! @[prepare_method], @[do_sync], @[do_async], @[wait] + //! @note + //! @[do_thread] does not rerun redirections automatically       Request do_thread(array(string|int|mapping) args)    { -  +  if(!con) con=give_me_connection(url_requested);    con->thread_request(@args);    return this_object();    }      //! Wait for the request thread to finish.   //! @returns   //! 0 upon failure, or the called object upon success.   //! @seealso   //! @[do_thread]   
pike.git/lib/modules/Protocols.pmod/HTTP.pmod/Session.pike:239:   //! thread is free).   //! Call @[set_callbacks] to setup the callbacks.   //! Get arguments from @[prepare_method].   //! @returns   //! The called object.   //! @seealso   //! @[set_callbacks], @[prepare_method], @[do_sync], @[do_thread]       Request do_async(array(string|int|mapping) args)    { +  if(!con) +  { +  if (connections_host_n[connection_lookup(url_requested)]>= +  maximum_connections_per_server || +  (!connections_kept_n && +  connections_inuse_n>=maximum_total_connections)) +  { +  wait_for_connection(do_async,args); +  return this_object(); +  } +  con=give_me_connection(url_requested); +  }    con->set_callbacks(async_ok,async_fail);    con->async_request(@args);    return this_object();    }       static void async_ok(object q)    {    check_for_cookies();       if (con->status>=300 && con->status<400 &&
pike.git/lib/modules/Protocols.pmod/HTTP.pmod/Session.pike:267:    follow_redirects--;       do_async(prepare_method("GET",loc));    return;    }    }       if (headers_callback)    headers_callback(@extra_callback_arguments);    +  // clear callbacks for possible garbation of this Request object +  con->set_callbacks(0,0); +     if (data_callback)    con->async_fetch(async_data); // start data downloading -  +  else +  extra_callback_arguments=0; // to allow garb    }       static void async_fail(object q)    { -  if (fail_callback) -  fail_callback(@extra_callback_arguments); +  // clear callbacks for possible garbation of this Request object +  con->set_callbacks(0,0); +  +  if (fail_callback) fail_callback(@extra_callback_arguments); +  extra_callback_arguments=0; // clear references there too    }       static void async_data()    { -  if (data_callback) -  data_callback(@extra_callback_arguments); +  // clear callbacks for possible garbation of this Request object +  con->set_callbacks(0,0); +  +  if (data_callback) data_callback(@extra_callback_arguments); +  extra_callback_arguments=0; // clear references there too    }    -  +  void wait_for_connection(function callback,mixed ...args) +  { +  freed_connection_callbacks+=({({connection_lookup(url_requested), +  callback,args})}); +  } +    // ----------------   // shortcuts to the Query object       string data()    {    if (!con) error("Request: no connection\n");    return con->data();    }       mapping headers()
pike.git/lib/modules/Protocols.pmod/HTTP.pmod/Session.pike:546:   //! The time to keep unused connections in seconds. Set to zero   //! to never save any kept-alive connections.   //! (Might be good in a for instance totaly synchroneous script   //! that keeps the backend thread busy and never will get call_outs.)   //! Defaults to 10 seconds.   int|float time_to_keep_unused_connections=10;      //! Maximum number of connections to the same server.   //! Used only by async requests.   //! Defaults to 10 connections. - //! @bugs - //! Not yet implemented. +    int maximum_connections_per_server=10;      //! Maximum total number of connections. Limits only   //! async requests, and the number of kept-alive connections   //! (live connections + kept-alive connections <= this number)   //! Defaults to 50 connections. - //! @bugs - //! Limit not yet implemented for async. +    int maximum_total_connections=50;            // internal (but readable for debug purposes)   mapping(string:array(KeptConnection)) connection_cache=([]);   int connections_kept_n=0;   int connections_inuse_n=0; -  + mapping(string:int) connections_host_n=([]);      static class KeptConnection   {    string lookup;    Query q;       void create(string _lookup,Query _q)    {    lookup=_lookup;    q=_q;
pike.git/lib/modules/Protocols.pmod/HTTP.pmod/Session.pike:586:    connection_cache[lookup]=    (connection_cache[lookup]||({}))+({this_object()});    connections_kept_n++;    }       void disconnect()    {    connection_cache[lookup]-=({this_object()});    if (!sizeof(connection_cache[lookup]))    m_delete(connection_cache,lookup); +  remove_call_out(disconnect); // if called externally       if (q->con) destruct(q->con);    connections_kept_n--; -  +  if (!--connections_host_n[lookup]) +  m_delete(connections_host_n,lookup);    destruct(q);    destruct(this_object());    }       Query use()    {    connection_cache[lookup]-=({this_object()});    if (!sizeof(connection_cache[lookup]))    m_delete(connection_cache,lookup); -  +     remove_call_out(disconnect); -  +     connections_kept_n--;    return q; // subsequently, this object is removed (no refs)    }   }      static inline string connection_lookup(Standards.URI url)   {    return url->scheme+"://"+url->host+":"+url->port;   }   
pike.git/lib/modules/Protocols.pmod/HTTP.pmod/Session.pike:628:    if (array(KeptConnection) v =    connection_cache[connection_lookup(url)])    {    q=v[0]->use(); // removes itself    // clean up    q->buf="";    q->headerbuf="";    }    else    { +  if (connections_kept_n+connections_inuse_n+1 +  >= maximum_total_connections && +  sizeof(connection_cache)) +  { +  // close one if we have it kept +  array(KeptConnection) all=`+(@values(connection_cache)); +  KeptConnection one=all[random(sizeof(all))]; +  one->disconnect(); // removes itself +  } +     q=Query();    q->hostname_cache=hostname_cache; -  +  connections_host_n[connection_lookup(url)]++; // new    }    connections_inuse_n++;    return q;   }    -  + // + // called when there might be a free connection +  + // queue of what to call when we get new free connections + array(array) freed_connection_callbacks=({}); +  // ({lookup,callback,args}) +  + static inline void freed_connection(string lookup_freed) + { +  if (connections_inuse_n>=maximum_total_connections) +  return; +  +  foreach (freed_connection_callbacks;;array v) +  { +  [string lookup, function callback, array args]=v; +  if (lookup==lookup_freed || +  connections_host_n[lookup]< +  maximum_connections_per_server) +  { +  freed_connection_callbacks-=({v}); +  callback(@args); +  return; +  } +  } + } +    //! Return a previously used Query object to the keep-alive   //! storage. This function will determine if the given object   //! is suitable to keep or not by checking status and headers.      void return_connection(Standards.URI url,Query query)   {    connections_inuse_n--; -  +  string lookup=connection_lookup(url);    if (query->con)    {    if (query->headers->connection &&    lower_case(query->headers->connection)=="keep-alive" &&    connections_kept_n+connections_inuse_n    < maximum_total_connections &&    time_to_keep_unused_connections>0)    {    // clean up    query->set_callbacks(0,0); -  KeptConnection(connection_lookup(url),query); +  KeptConnection(lookup,query); +  freed_connection(lookup);    return;    }    destruct(query->con);    }    destruct(query); -  +  if (!--connections_host_n[lookup]) +  m_delete(connections_host_n,lookup); +  freed_connection(lookup);   }      // ================================================================      Request do_method(string method,    string url,    void|mapping query_variables,    void|string data)   {    mapping extra_headers=0;
pike.git/lib/modules/Protocols.pmod/HTTP.pmod/Session.pike:811:    mapping query_variables)   {    Request z = post_url(url, query_variables);    return z && z->data();   }      // ================================================================   // async operation      Request async_do_method(string method, -  string url, +  Standards.URI|string url,    void|mapping query_variables,    void|string data,    function callback_headers_ok,    function callback_data_ok,    function callback_fail,    array callback_arguments)   { -  mapping extra_headers=0; -  if (method=="POST") -  extra_headers=(["content-type":"application/x-www-form-urlencoded"]); +  if(stringp(url)) url=Standards.URI(url);       Request p=Request(); -  +     p->set_callbacks(callback_headers_ok,    callback_data_ok,    callback_fail,    p,@callback_arguments); -  +  +  mapping extra_headers=0; +  if (method=="POST") +  extra_headers=(["content-type":"application/x-www-form-urlencoded"]); +     p->do_async(p->prepare_method(method,url,query_variables,    extra_headers,data));    return p;   }         //! @decl Request async_get_url(string|Standards.URI url,   //! void|mapping query_variables,   //! function callback_headers_ok,   //! function callback_data_ok,