Roxen.git / server / base_server / roxen.pike

version» Context lines:

Roxen.git/server/base_server/roxen.pike:1:   // This file is part of Roxen WebServer.   // Copyright © 1996 - 2009, Roxen IS.   //   // The Roxen WebServer main program.   //   // Per Hedbor, Henrik Grubbström, Pontus Hagland, David Hedbor and others.   // ABS and suicide systems contributed freely by Francesco Chemolli    - constant cvs_version="$Id: roxen.pike,v 1.1080 2011/02/15 13:51:39 marty Exp $"; + constant cvs_version="$Id: roxen.pike,v 1.1081 2011/06/15 15:11:08 grubba Exp $";      //! @appears roxen   //!   //! The Roxen WebServer main program.      // The argument cache. Used by the image cache.   ArgCache argcache;      // Some headerfiles   #define IN_ROXEN
Roxen.git/server/base_server/roxen.pike:1801:    //! The protocol handler for this URL.    //! @member int "mib_version"    //! (Only SNMP). The version number for the configuration MIB    //! tree when it was last merged.    //! @endmapping       mapping(Configuration:mapping(string:mixed)) conf_data = ([]);    //! Maps the configuration objects to the data mappings in @[urls].       void ref(string name, mapping(string:mixed) data) -  //! Add a ref for the URL 'name' with the data 'data' +  //! Add a ref for the URL @[name] with the data @[data]. +  //! +  //! See @[urls] for documentation about the supported +  //! fields in @[data].    {    if(urls[name])    {    conf_data[urls[name]->conf] = urls[name] = data;    return; // only ref once per URL    }    if (!refs) path = data->path;    else if (path != (data->path || "")) path = 0;    refs++;    mu = 0;
Roxen.git/server/base_server/roxen.pike:2593:   #endif    };    }    report_debug("\bDone [%.1fms]\n", (gethrtime()-st)/1000.0 );    return protocols;   }         mapping(string:program/*(Protocol)*/) protocols;    - // prot:ip:port ==> Protocol. + //! Lookup from protocol, IP number and port to + //! the corresponding open @[Protocol] port. + //! + //! @mapping + //! @member mapping(string:mapping(int:Protocol)) protocol_name + //! @mapping + //! @member mapping(int:Protocol) ip_number + //! @mapping + //! @member Protocol port_number + //! @[Protocol] object that holds this ip_number and port open. + //! @endmapping + //! @endmapping + //! @endmapping   mapping(string:mapping(string:mapping(int:Protocol))) open_ports = ([ ]);    - // url:"port" ==> Protocol. + //! Lookup from URL string to the corresponding open @[Protocol] ports. + //! + //! Note that there are two classes of URL strings used as indices in + //! this mapping: + //! @dl + //! @item "prot://host_glob:port/path/" + //! A normalized URL string as returned by @[normalize_url()]. + //! + //! @[Protocol()->ref()] in the contained ports as been called + //! with the url. + //! + //! @item "port://host_glob:port/path/#opt1=val1;opt2=val2" + //! An URL string containing options as stored in the @tt{"URLs"@} + //! configuration variable, and expected as argument by + //! @[register_url()] and @[unregister_url()]. Also known + //! as an ourl. + //! @enddl + //! + //! In both cases the same set of data is stored: + //! @mapping + //! @member mapping(string:Configuration|Protocol|string|array(Protocol)) url + //! @mapping + //! @member Protocol "port" + //! Representative open port for this URL. + //! @member array(Protocol) "ports" + //! Array of all open ports for this URL. + //! @member Configuration "conf" + //! Configuration that has registered the URL. + //! @member string "path" + //! Path segment of the URL. + //! @member string "host" + //! Hostname segment of the URL. + //! @endmapping + //! @endmapping   mapping(string:mapping(string:Configuration|Protocol|string|array(Protocol)))    urls = ([]); -  +    array sorted_urls = ({});      array(string) find_ips_for( string what )   {    if( what == "*" || lower_case(what) == "any" )    return ({   #if constant(__ROXEN_SUPPORTS_IPV6__)    "::",   #endif /* __ROXEN_SUPPORTS_IPV6__ */    0,
Roxen.git/server/base_server/roxen.pike:2698:    // "/", but not end with one.    path);    }       else {    ui->fragment = 0;    return (string) ui;    }   }    + //! Unregister an URL from a configuration. + //! + //! @seealso + //! @[register_url()]   void unregister_url(string url, Configuration conf)   {    string ourl = url; -  +  mapping(string:mixed) data = m_delete(urls, ourl); +  if (!data) return; // URL not registered.    if (!sizeof(url = normalize_url(url, 1))) return;       report_debug ("Unregister %s%s.\n", normalize_url (ourl),    conf ? sprintf (" for %O", conf->query_name()) : "");    -  if (urls[url] && (!conf || !urls[url]->conf || (urls[url]->conf == conf)) && -  urls[url]->port) -  { -  urls[ url ]->port->unref(url); -  m_delete( urls, url ); -  m_delete( urls, ourl ); -  sort_urls(); +  mapping(string:mixed) shared_data = urls[url]; +  if (!shared_data) return; // Strange case, but URL not registered. +  +  foreach(data->ports, Protocol port) { +  shared_data->ports -= ({ port }); +  int was_main_port = (shared_data->port == port); +  port->unref(url); +  m_delete(shared_data, "port");    } -  +  if (!sizeof(shared_data->ports)) { +  m_delete(urls, url); +  } else if (!shared_data->port) { +  shared_data->port = shared_data->ports[0];    } -  +  sort_urls(); + }      array all_ports( )   { -  return Array.uniq( values( urls )->port )-({0}); +  // FIXME: Consider using open_ports instead. +  return Array.uniq( values( urls )->ports * ({}) )-({0});   }      Protocol find_port( string name )   {    foreach( all_ports(), Protocol p )    if( p->get_key() == name )    return p;   }      void sort_urls()   {    sorted_urls = indices( urls );    sort( map( map( sorted_urls, strlen ), `-), sorted_urls );   }    -  + //! Register an URL for a configuration. + //! + //! @seealso + //! @[unregister_url()]   int register_url( string url, Configuration conf )   {    string ourl = url;    if (!sizeof (url - " " - "\t")) return 1;       Standards.URI ui = Standards.URI(url);    mapping opts = ([]);    string a, b;    foreach( (ui->fragment||"")/";", string x )    {
Roxen.git/server/base_server/roxen.pike:2788:    else if( urls[ url ]->conf )    {    if( urls[ url ]->conf != conf )    {    report_error(LOC_M(20,    "Cannot register URL %s - "    "already registered by %s.")+"\n",    display_url, urls[ url ]->conf->name);    return 0;    } +  // FIXME: Is this correct?    urls[ url ]->port->ref(url, urls[url]); -  return 1; +     }    else    urls[ url ]->port->unref( url );    }       program prot;       if( !( prot = protocols[ protocol ] ) )    {    report_error(LOC_M(21, "Cannot register URL %s - "    "cannot find the protocol %s.")+"\n",    display_url, protocol);    return 0;    }    -  urls[ url ] = ([ "conf":conf, "path":path, "hostname": host ]); -  urls[ ourl ] = urls[url] + ([]); -  sorted_urls += ({ url }); +  if (!urls[ourl]) +  urls[ ourl ] = ([ "conf":conf, "path":path, "hostname": host ]); +  if (!urls[url]) { +  urls[ url ] = urls[ourl] + ([]); +  sorted_urls += ({ url }); // FIXME: Not exactly sorted... +  }       array(string)|int(-1..0) required_hosts;       if (is_ip(host))    required_hosts = ({ host });    else if(!sizeof(required_hosts =    filter(replace(opts->ip||"", " ","")/",", is_ip)) ) {    required_hosts = find_ips_for( host );    if (!required_hosts) {    // FIXME: Used to fallback to ANY.
Roxen.git/server/base_server/roxen.pike:2835:    // always add 'ANY' (0) and 'IPv6_ANY' (::) here, as empty mappings,    // for speed reasons.    // There is now no need to check for both open_ports[prot][0] and    // open_ports[prot][0][port], we can go directly to the latter    // test.    m = open_ports[ protocol ] = ([ 0:([]), "::":([]) ]);       if (prot->supports_ipless ) {    // Check if the ANY port is already open for this port, since this    // protocol supports IP-less virtual hosting, there is no need to -  // open yet another port if it is, since that would mosts probably +  // open yet another port if it is, since that would most probably    // only conflict with the ANY port anyway. (this is true on most    // OSes, it works on Solaris, but fails on linux)    array(string) ipv6 = filter(required_hosts - ({ 0 }), has_value, ":");    array(string) ipv4 = required_hosts - ipv6;    if (m[0][port] && sizeof(ipv4 - ({ 0 }))) {    // We have a non-ANY IPv4 IP number.    ipv4 = ({ 0 });    }   #if constant(__ROXEN_SUPPORTS_IPV6__)    if (m["::"][port] && sizeof(ipv6 - ({ "::" }))) {
Roxen.git/server/base_server/roxen.pike:2874:       foreach(required_hosts, string required_host)    {    if( m[ required_host ] && m[ required_host ][ port ] )    {    if (required_host == "::") opened_ipv6_any_port = 1;       m[required_host][port]->ref(url, urls[url]);       urls[url]->port = m[required_host][port]; +  if (urls[url]->ports) { +  urls[url]->ports += ({ m[required_host][port] }); +  } else { +  urls[url]->ports = ({ m[required_host][port] }); +  }    urls[ourl]->port = m[required_host][port];    if (urls[ourl]->ports) {    urls[ourl]->ports += ({ m[required_host][port] });    } else {    urls[ourl]->ports = ({ m[required_host][port] });    }    continue; /* No need to open a new port */    }       if( !m[ required_host ] )    m[ required_host ] = ([ ]);          Protocol prot_obj;    if (mixed err = catch {    prot_obj = m[ required_host ][ port ] =    prot( port, required_host,    // Don't complain if binding IPv4 ANY fails with    // EADDRINUSE after we've bound IPv6 ANY. -  // Most systems seems to bind booth IPv4 ANY and +  // Most systems seems to bind both IPv4 ANY and    // IPv6 ANY for "::"    !required_host && opened_ipv6_any_port);    }) {    failures++;   #if 0    if (has_prefix(describe_error(err), "Invalid address") &&    required_host && has_value(required_host, ":")) {    report_error(sprintf("Failed to initialize IPv6 port for URL %s"    " (ip %s).\n",    display_url, required_host));
Roxen.git/server/base_server/roxen.pike:2929:    if (required_host == "::") opened_ipv6_any_port = 1;       if (prot_obj->bound == -1) {    // Got EADDRINUSE for the IPv6 case - see above. Just forget    // about this one.    m_delete (m[required_host], port);    continue;    }       urls[ url ]->port = prot_obj; +  if (urls[url]->ports) { +  urls[url]->ports += ({ prot_obj }); +  } else { +  urls[url]->ports = ({ prot_obj }); +  }    urls[ ourl ]->port = prot_obj;    if (urls[ourl]->ports) {    urls[ourl]->ports += ({ prot_obj });    } else {    urls[ourl]->ports = ({ prot_obj });    }    prot_obj->ref(url, urls[url]);       if( !prot_obj->bound )    failures++;