• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

RecHttp.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   HTTP configuration support.
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022 */
00023 
00024 # include <records/I_RecCore.h>
00025 # include <records/I_RecHttp.h>
00026 # include <ts/ink_defs.h>
00027 # include <ts/Tokenizer.h>
00028 # include <strings.h>
00029 
00030 SessionProtocolNameRegistry globalSessionProtocolNameRegistry;
00031 
00032 /* Protocol session well-known protocol names.
00033    These are also used for NPN setup.
00034 */
00035 
00036 const char * const TS_NPN_PROTOCOL_HTTP_0_9 = "http/0.9";
00037 const char * const TS_NPN_PROTOCOL_HTTP_1_0 = "http/1.0";
00038 const char * const TS_NPN_PROTOCOL_HTTP_1_1 = "http/1.1";
00039 const char * const TS_NPN_PROTOCOL_HTTP_2_0 = "h2-12";    // draft-ietf-httpbis-http2-12
00040 const char * const TS_NPN_PROTOCOL_SPDY_1   = "spdy/1";   // obsolete
00041 const char * const TS_NPN_PROTOCOL_SPDY_2   = "spdy/2";
00042 const char * const TS_NPN_PROTOCOL_SPDY_3   = "spdy/3";
00043 const char * const TS_NPN_PROTOCOL_SPDY_3_1 = "spdy/3.1";
00044 
00045 const char * const TS_NPN_PROTOCOL_GROUP_HTTP = "http";
00046 const char * const TS_NPN_PROTOCOL_GROUP_HTTP2 = "http2";
00047 const char * const TS_NPN_PROTOCOL_GROUP_SPDY = "spdy";
00048 
00049 // Precomputed indices for ease of use.
00050 int TS_NPN_PROTOCOL_INDEX_HTTP_0_9 = SessionProtocolNameRegistry::INVALID;
00051 int TS_NPN_PROTOCOL_INDEX_HTTP_1_0 = SessionProtocolNameRegistry::INVALID;
00052 int TS_NPN_PROTOCOL_INDEX_HTTP_1_1 = SessionProtocolNameRegistry::INVALID;
00053 int TS_NPN_PROTOCOL_INDEX_HTTP_2_0 = SessionProtocolNameRegistry::INVALID;
00054 int TS_NPN_PROTOCOL_INDEX_SPDY_1 = SessionProtocolNameRegistry::INVALID;
00055 int TS_NPN_PROTOCOL_INDEX_SPDY_2 = SessionProtocolNameRegistry::INVALID;
00056 int TS_NPN_PROTOCOL_INDEX_SPDY_3 = SessionProtocolNameRegistry::INVALID;
00057 int TS_NPN_PROTOCOL_INDEX_SPDY_3_1 = SessionProtocolNameRegistry::INVALID;
00058 
00059 // Predefined protocol sets for ease of use.
00060 SessionProtocolSet HTTP_PROTOCOL_SET;
00061 SessionProtocolSet SPDY_PROTOCOL_SET;
00062 SessionProtocolSet HTTP2_PROTOCOL_SET;
00063 SessionProtocolSet DEFAULT_NON_TLS_SESSION_PROTOCOL_SET;
00064 SessionProtocolSet DEFAULT_TLS_SESSION_PROTOCOL_SET;
00065 
00066 void RecHttpLoadIp(char const* value_name, IpAddr& ip4, IpAddr& ip6)
00067 {
00068   char value[1024];
00069   ip4.invalidate();
00070   ip6.invalidate();
00071   if (REC_ERR_OKAY == RecGetRecordString(value_name, value, sizeof(value))) {
00072     Tokenizer tokens(", ");
00073     int n_addrs = tokens.Initialize(value);
00074     for (int i = 0 ; i < n_addrs ; ++i ) {
00075       char const* host = tokens[i];
00076       IpEndpoint tmp4, tmp6;
00077       // For backwards compatibility we need to support the use of host names
00078       // for the address to bind.
00079       if (0 == ats_ip_getbestaddrinfo(host, &tmp4, &tmp6)) {
00080         if (ats_is_ip4(&tmp4)) {
00081           if (!ip4.isValid()) ip4 = tmp4;
00082           else Warning("'%s' specifies more than one IPv4 address, ignoring %s.", value_name, host);
00083         }
00084         if (ats_is_ip6(&tmp6)) {
00085           if (!ip6.isValid()) ip6 = tmp6;
00086           else Warning("'%s' specifies more than one IPv6 address, ignoring %s.", value_name, host);
00087         }
00088       } else {
00089         Warning("'%s' has an value '%s' that is not recognized as an IP address, ignored.", value_name, host);
00090       }
00091     }
00092   }
00093 }
00094 
00095 
00096 char const* const HttpProxyPort::DEFAULT_VALUE = "8080";
00097 
00098 char const* const HttpProxyPort::PORTS_CONFIG_NAME = "proxy.config.http.server_ports";
00099 
00100 // "_PREFIX" means the option contains additional data.
00101 // Each has a corresponding _LEN value that is the length of the option text.
00102 // Options without _PREFIX are just flags with no additional data.
00103 
00104 char const* const HttpProxyPort::OPT_FD_PREFIX = "fd";
00105 char const* const HttpProxyPort::OPT_OUTBOUND_IP_PREFIX = "ip-out";
00106 char const* const HttpProxyPort::OPT_INBOUND_IP_PREFIX = "ip-in";
00107 char const* const HttpProxyPort::OPT_HOST_RES_PREFIX = "ip-resolve";
00108 char const* const HttpProxyPort::OPT_PROTO_PREFIX = "proto";
00109 
00110 char const* const HttpProxyPort::OPT_IPV6 = "ipv6";
00111 char const* const HttpProxyPort::OPT_IPV4 = "ipv4";
00112 char const* const HttpProxyPort::OPT_TRANSPARENT_INBOUND = "tr-in";
00113 char const* const HttpProxyPort::OPT_TRANSPARENT_OUTBOUND = "tr-out";
00114 char const* const HttpProxyPort::OPT_TRANSPARENT_FULL = "tr-full";
00115 char const* const HttpProxyPort::OPT_TRANSPARENT_PASSTHROUGH = "tr-pass";
00116 char const* const HttpProxyPort::OPT_SSL = "ssl";
00117 char const* const HttpProxyPort::OPT_PLUGIN = "plugin";
00118 char const* const HttpProxyPort::OPT_BLIND_TUNNEL = "blind";
00119 char const* const HttpProxyPort::OPT_COMPRESSED = "compressed";
00120 
00121 // File local constants.
00122 namespace {
00123   // Length values for _PREFIX options.
00124   size_t const OPT_FD_PREFIX_LEN = strlen(HttpProxyPort::OPT_FD_PREFIX);
00125   size_t const OPT_OUTBOUND_IP_PREFIX_LEN = strlen(HttpProxyPort::OPT_OUTBOUND_IP_PREFIX);
00126   size_t const OPT_INBOUND_IP_PREFIX_LEN = strlen(HttpProxyPort::OPT_INBOUND_IP_PREFIX);
00127   size_t const OPT_HOST_RES_PREFIX_LEN = strlen(HttpProxyPort::OPT_HOST_RES_PREFIX);
00128   size_t const OPT_PROTO_PREFIX_LEN = strlen(HttpProxyPort::OPT_PROTO_PREFIX);
00129 }
00130 
00131 namespace {
00132 // Solaris work around. On that OS the compiler will not let me use an
00133 // instantiated instance of Vec<self> inside the class, even if
00134 // static. So we have to declare it elsewhere and then import via
00135 // reference. Might be a problem with Vec<> creating a fixed array
00136 // rather than allocating on first use (compared to std::vector<>).
00137   HttpProxyPort::Group GLOBAL_DATA;
00138 }
00139 HttpProxyPort::Group& HttpProxyPort::m_global = GLOBAL_DATA;
00140 
00141 HttpProxyPort::HttpProxyPort()
00142   : m_fd(ts::NO_FD)
00143   , m_type(TRANSPORT_DEFAULT)
00144   , m_port(0)
00145   , m_family(AF_INET)
00146   , m_inbound_transparent_p(false)
00147   , m_outbound_transparent_p(false)
00148   , m_transparent_passthrough(false)
00149 {
00150   memcpy(m_host_res_preference, host_res_default_preference_order, sizeof(m_host_res_preference));
00151 }
00152 
00153 bool HttpProxyPort::hasSSL(Group const& ports) {
00154   bool zret = false;
00155   for ( int i = 0 , n = ports.length() ; i < n && !zret ; ++i ) {
00156     if (ports[i].isSSL()) zret = true;
00157   }
00158   return zret;
00159 }
00160 
00161 HttpProxyPort* HttpProxyPort::findHttp(Group const& ports, uint16_t family) {
00162   bool check_family_p = ats_is_ip(family);
00163   self* zret = 0;
00164   for ( int i = 0 , n = ports.length() ; i < n && !zret ; ++i ) {
00165     HttpProxyPort& p = ports[i];
00166     if (p.m_port && // has a valid port
00167         TRANSPORT_DEFAULT == p.m_type && // is normal HTTP
00168         ( !check_family_p || p.m_family == family) // right address family
00169         )
00170       zret = &p;;
00171   }
00172   return zret;
00173 }
00174 
00175 char const*
00176 HttpProxyPort::checkPrefix(char const* src, char const* prefix, size_t prefix_len) {
00177   char const* zret = 0;
00178   if (0 == strncasecmp(prefix, src, prefix_len)) {
00179     src += prefix_len;
00180     if ('-' == *src || '=' == *src) ++src; // permit optional '-' or '='
00181     zret = src;
00182   }
00183   return zret;
00184 }
00185 
00186 bool
00187 HttpProxyPort::loadConfig(Vec<self>& entries) {
00188   char* text;
00189   bool found_p;
00190 
00191   text = REC_readString(PORTS_CONFIG_NAME, &found_p);
00192   if (found_p) self::loadValue(entries, text);
00193   ats_free(text);
00194 
00195   return 0 < entries.length();
00196 }
00197 
00198 bool
00199 HttpProxyPort::loadDefaultIfEmpty(Group& ports) {
00200   if (0 == ports.length())
00201     self::loadValue(ports, DEFAULT_VALUE);
00202 
00203   return 0 < ports.length();
00204 }
00205 
00206 bool
00207 HttpProxyPort::loadValue(Vec<self>& ports, char const* text) {
00208   unsigned old_port_length = ports.length(); // remember this.
00209   if (text && *text) {
00210     Tokenizer tokens(", ");
00211     int n_ports = tokens.Initialize(text);
00212     if (n_ports > 0) {
00213       for ( int p = 0 ; p < n_ports ; ++p ) {
00214         char const* elt = tokens[p];
00215         HttpProxyPort entry;
00216         if (entry.processOptions(elt)) ports.push_back(entry);
00217         else Warning("No valid definition was found in proxy port configuration element '%s'", elt);
00218       }
00219     }
00220   }
00221   return ports.length() > old_port_length; // we added at least one port.
00222 }
00223 
00224 bool
00225 HttpProxyPort::processOptions(char const* opts) {
00226   bool zret = false; // found a port?
00227   bool af_set_p = false; // AF explicitly specified?
00228   bool host_res_set_p = false; // Host resolution order set explicitly?
00229   bool sp_set_p = false; // Session protocol set explicitly?
00230   bool bracket_p = false; // found an open bracket in the input?
00231   char const* value; // Temp holder for value of a prefix option.
00232   IpAddr ip; // temp for loading IP addresses.
00233   Vec<char*> values; // Pointers to single option values.
00234 
00235   // Make a copy we can modify safely.
00236   size_t opts_len = strlen(opts) + 1;
00237   char* text = static_cast<char*>(alloca(opts_len));
00238   memcpy(text, opts, opts_len);
00239 
00240   // Split the copy in to tokens.
00241   char* token = 0;
00242   for (char* spot = text ; *spot ; ++spot ) {
00243     if (bracket_p) {
00244       if (']' == *spot) bracket_p = false;
00245     } else if (':' == *spot) {
00246       *spot = 0;
00247       token = 0;
00248     } else {
00249       if (! token) {
00250         token = spot;
00251         values.push_back(token);
00252       }
00253       if ('[' == *spot) bracket_p = true;
00254     }
00255   }
00256   if (bracket_p) {
00257     Warning("Invalid port descriptor '%s' - left bracket without closing right bracket", opts);
00258     return zret;
00259   }
00260 
00261   for ( int i = 0, n_items = values.length() ; i < n_items ; ++i) {
00262     char const* item = values[i];
00263     if (isdigit(item[0])) { // leading digit -> port value
00264       char* ptr;
00265       int port = strtoul(item, &ptr, 10);
00266       if (ptr == item) {
00267         // really, this shouldn't happen, since we checked for a leading digit.
00268         Warning("Mangled port value '%s' in port configuration '%s'", item, opts);
00269       } else if (port <= 0 || 65536 <= port) {
00270         Warning("Port value '%s' out of range (1..65535) in port configuration '%s'", item, opts);
00271       } else {
00272         m_port = port;
00273         zret = true;
00274       }
00275     } else if (0 != (value = this->checkPrefix(item, OPT_FD_PREFIX, OPT_FD_PREFIX_LEN))) {
00276       char* ptr; // tmp for syntax check.
00277       int fd = strtoul(value, &ptr, 10);
00278       if (ptr == value) {
00279         Warning("Mangled file descriptor value '%s' in port descriptor '%s'", item, opts);
00280       } else {
00281         m_fd = fd;
00282         zret = true;
00283       }
00284     } else if (0 != (value = this->checkPrefix(item, OPT_INBOUND_IP_PREFIX, OPT_INBOUND_IP_PREFIX_LEN))) {
00285       if (0 == ip.load(value))
00286         m_inbound_ip = ip;
00287       else
00288         Warning("Invalid IP address value '%s' in port descriptor '%s'",
00289           item, opts
00290         );
00291     } else if (0 != (value = this->checkPrefix(item, OPT_OUTBOUND_IP_PREFIX, OPT_OUTBOUND_IP_PREFIX_LEN))) {
00292       if (0 == ip.load(value))
00293         this->outboundIp(ip.family()) = ip;
00294       else
00295         Warning("Invalid IP address value '%s' in port descriptor '%s'", item, opts);
00296     } else if (0 == strcasecmp(OPT_COMPRESSED, item)) {
00297       m_type = TRANSPORT_COMPRESSED;
00298     } else if (0 == strcasecmp(OPT_BLIND_TUNNEL, item)) {
00299       m_type = TRANSPORT_BLIND_TUNNEL;
00300     } else if (0 == strcasecmp(OPT_IPV6, item)) {
00301       m_family = AF_INET6;
00302       af_set_p = true;
00303     } else if (0 == strcasecmp(OPT_IPV4, item)) {
00304       m_family = AF_INET;
00305       af_set_p = true;
00306     } else if (0 == strcasecmp(OPT_SSL, item)) {
00307       m_type = TRANSPORT_SSL;
00308     } else if (0 == strcasecmp(OPT_PLUGIN, item)) {
00309       m_type = TRANSPORT_PLUGIN;
00310     } else if (0 == strcasecmp(OPT_TRANSPARENT_INBOUND, item)) {
00311 # if TS_USE_TPROXY
00312       m_inbound_transparent_p = true;
00313 # else
00314       Warning("Transparency requested [%s] in port descriptor '%s' but TPROXY was not configured.", item, opts);
00315 # endif
00316     } else if (0 == strcasecmp(OPT_TRANSPARENT_OUTBOUND, item)) {
00317 # if TS_USE_TPROXY
00318       m_outbound_transparent_p = true;
00319 # else
00320       Warning("Transparency requested [%s] in port descriptor '%s' but TPROXY was not configured.", item, opts);
00321 # endif
00322     } else if (0 == strcasecmp(OPT_TRANSPARENT_FULL, item)) {
00323 # if TS_USE_TPROXY
00324       m_inbound_transparent_p = true;
00325       m_outbound_transparent_p = true;
00326 # else
00327       Warning("Transparency requested [%s] in port descriptor '%s' but TPROXY was not configured.", item, opts);
00328 # endif
00329     } else if (0 == strcasecmp(OPT_TRANSPARENT_PASSTHROUGH, item)) {
00330 # if TS_USE_TPROXY
00331       m_transparent_passthrough = true;
00332 # else
00333       Warning("Transparent pass-through requested [%s] in port descriptor '%s' but TPROXY was not configured.", item, opts);
00334 # endif
00335     } else if (0 != (value = this->checkPrefix(item, OPT_HOST_RES_PREFIX, OPT_HOST_RES_PREFIX_LEN))) {
00336       this->processFamilyPreference(value);
00337       host_res_set_p = true;
00338     } else if (0 != (value = this->checkPrefix(item, OPT_PROTO_PREFIX, OPT_PROTO_PREFIX_LEN))) {
00339       this->processSessionProtocolPreference(value);
00340       sp_set_p = true;
00341     } else {
00342       Warning("Invalid option '%s' in proxy port configuration '%s'", item, opts);
00343     }
00344   }
00345 
00346   bool in_ip_set_p = m_inbound_ip.isValid();
00347 
00348   if (af_set_p) {
00349     if (in_ip_set_p && m_family != m_inbound_ip.family()) {
00350       Warning("Invalid port descriptor '%s' - the inbound adddress family [%s] is not the same type as the explicit family value [%s]",
00351         opts, ats_ip_family_name(m_inbound_ip.family()), ats_ip_family_name(m_family));
00352       zret = false;
00353     }
00354   } else if (in_ip_set_p) {
00355     m_family = m_inbound_ip.family(); // set according to address.
00356   }
00357 
00358   // If the port is outbound transparent only CLIENT host resolution is possible.
00359   if (m_outbound_transparent_p) {
00360     if (host_res_set_p &&
00361         (m_host_res_preference[0] != HOST_RES_PREFER_CLIENT ||
00362          m_host_res_preference[1] != HOST_RES_PREFER_NONE
00363     )) {
00364       Warning("Outbound transparent port '%s' requires the IP address resolution ordering '%s,%s'. "
00365               "This is set automatically and does not need to be set explicitly."
00366               , opts
00367               , HOST_RES_PREFERENCE_STRING[HOST_RES_PREFER_CLIENT]
00368               , HOST_RES_PREFERENCE_STRING[HOST_RES_PREFER_NONE]
00369         );
00370     }
00371     m_host_res_preference[0] = HOST_RES_PREFER_CLIENT;
00372     m_host_res_preference[1] = HOST_RES_PREFER_NONE;
00373   }
00374 
00375   // Transparent pass-through requires tr-in
00376   if (m_transparent_passthrough && !m_inbound_transparent_p) {
00377     Warning("Port descriptor '%s' has transparent pass-through enabled without inbound transparency, this will be ignored.", opts);
00378     m_transparent_passthrough = false;
00379   }
00380 
00381   // Set the default session protocols.
00382   if (!sp_set_p)
00383     m_session_protocol_preference = this->isSSL()
00384       ? DEFAULT_TLS_SESSION_PROTOCOL_SET
00385       : DEFAULT_NON_TLS_SESSION_PROTOCOL_SET
00386       ;
00387 
00388   return zret;
00389 }
00390 
00391 void
00392 HttpProxyPort::processFamilyPreference(char const* value) {
00393   parse_host_res_preference(value, m_host_res_preference);
00394 }
00395 
00396 void
00397 HttpProxyPort::processSessionProtocolPreference(char const* value) {
00398   m_session_protocol_preference.markAllOut();
00399   globalSessionProtocolNameRegistry.markIn(value, m_session_protocol_preference);
00400 }
00401 
00402 void
00403 SessionProtocolNameRegistry::markIn(char const* value, SessionProtocolSet& sp_set) {
00404   int n; // # of tokens
00405   Tokenizer tokens(" ;|,:");
00406  
00407   n = tokens.Initialize(value);
00408 
00409   for ( int i = 0 ; i < n ; ++i ) {
00410     char const* elt = tokens[i];
00411     
00412     /// Check special cases
00413     if (0 == strcasecmp(elt, TS_NPN_PROTOCOL_GROUP_HTTP)) {
00414       sp_set.markIn(HTTP_PROTOCOL_SET);
00415     } else if (0 == strcasecmp(elt, TS_NPN_PROTOCOL_GROUP_SPDY)) {
00416       sp_set.markIn(SPDY_PROTOCOL_SET);
00417     } else if (0 == strcasecmp(elt, TS_NPN_PROTOCOL_GROUP_HTTP2)) {
00418       sp_set.markIn(HTTP2_PROTOCOL_SET);
00419     } else { // user defined - register and mark.
00420       int idx = globalSessionProtocolNameRegistry.toIndex(elt);
00421       sp_set.markIn(idx);
00422     }
00423   }
00424 }
00425 
00426 int
00427 HttpProxyPort::print(char* out, size_t n) {
00428   size_t zret = 0; // # of chars printed so far.
00429   ip_text_buffer ipb;
00430   bool need_colon_p = false;
00431 
00432   if (m_inbound_ip.isValid()) {
00433     zret += snprintf(out+zret, n-zret, "%s=[%s]",
00434       OPT_INBOUND_IP_PREFIX,
00435       m_inbound_ip.toString(ipb, sizeof(ipb))
00436     );
00437     need_colon_p = true;
00438   }
00439   if (zret >= n) return n;
00440 
00441   if (m_outbound_ip4.isValid()) {
00442     if (need_colon_p) out[zret++] = ':';
00443     zret += snprintf(out+zret, n-zret, "%s=[%s]",
00444       OPT_OUTBOUND_IP_PREFIX,
00445       m_outbound_ip4.toString(ipb, sizeof(ipb))
00446     );
00447     need_colon_p = true;
00448   }
00449   if (zret >= n) return n;
00450 
00451   if (m_outbound_ip6.isValid()) {
00452     if (need_colon_p) out[zret++] = ':';
00453     zret += snprintf(out+zret, n-zret, "%s=[%s]",
00454       OPT_OUTBOUND_IP_PREFIX,
00455       m_outbound_ip6.toString(ipb, sizeof(ipb))
00456     );
00457     need_colon_p = true;
00458   }
00459   if (zret >= n) return n;
00460 
00461   if (0 != m_port) {
00462     if (need_colon_p) out[zret++] = ':';
00463     zret += snprintf(out+zret, n-zret, "%d", m_port);
00464     need_colon_p = true;
00465   }
00466   if (zret >= n) return n;
00467 
00468   if (ts::NO_FD != m_fd) {
00469     if (need_colon_p) out[zret++] = ':';
00470     zret += snprintf(out+zret, n-zret, "fd=%d", m_fd);
00471   }
00472   if (zret >= n) return n;
00473 
00474   // After this point, all of these options require other options which we've already
00475   // generated so all of them need a leading colon and we can stop checking for that.
00476 
00477   if (AF_INET6 == m_family)
00478     zret += snprintf(out+zret, n-zret, ":%s", OPT_IPV6);
00479   if (zret >= n) return n;
00480 
00481   if (TRANSPORT_BLIND_TUNNEL == m_type)
00482     zret += snprintf(out+zret, n-zret, ":%s", OPT_BLIND_TUNNEL);
00483   else if (TRANSPORT_SSL == m_type)
00484     zret += snprintf(out+zret, n-zret, ":%s", OPT_SSL);
00485   else if (TRANSPORT_PLUGIN == m_type)
00486     zret += snprintf(out+zret, n-zret, ":%s", OPT_PLUGIN);
00487   else if (TRANSPORT_COMPRESSED == m_type)
00488     zret += snprintf(out+zret, n-zret, ":%s", OPT_COMPRESSED);
00489   if (zret >= n) return n;
00490 
00491   if (m_outbound_transparent_p && m_inbound_transparent_p)
00492     zret += snprintf(out+zret, n-zret, ":%s", OPT_TRANSPARENT_FULL);
00493   else if (m_inbound_transparent_p)
00494     zret += snprintf(out+zret, n-zret, ":%s", OPT_TRANSPARENT_INBOUND);
00495   else if (m_outbound_transparent_p)
00496     zret += snprintf(out+zret, n-zret, ":%s", OPT_TRANSPARENT_OUTBOUND);
00497 
00498   if (m_transparent_passthrough)
00499     zret += snprintf(out+zret, n-zret, ":%s", OPT_TRANSPARENT_PASSTHROUGH);
00500 
00501   /* Don't print the IP resolution preferences if the port is outbound
00502    * transparent (which means the preference order is forced) or if
00503    * the order is the same as the default.
00504    */
00505   if (!m_outbound_transparent_p &&
00506       0 != memcmp(m_host_res_preference, host_res_default_preference_order, sizeof(m_host_res_preference))) {
00507     zret += snprintf(out+zret, n-zret, ":%s=", OPT_HOST_RES_PREFIX);
00508     zret += ts_host_res_order_to_string(m_host_res_preference, out+zret, n-zret);
00509   }
00510 
00511   // session protocol options - look for condensed options first
00512   // first two cases are the defaults so if those match, print nothing.
00513   SessionProtocolSet sp_set = m_session_protocol_preference; // need to modify so copy.
00514   need_colon_p = true; // for listing case, turned off if we do a special case.
00515   if (sp_set == DEFAULT_NON_TLS_SESSION_PROTOCOL_SET && !this->isSSL()) {
00516     sp_set.markOut(DEFAULT_NON_TLS_SESSION_PROTOCOL_SET);
00517   } else if (sp_set == DEFAULT_TLS_SESSION_PROTOCOL_SET && this->isSSL()) {
00518     sp_set.markOut(DEFAULT_TLS_SESSION_PROTOCOL_SET);
00519   }
00520 
00521   // pull out groups.
00522   if (sp_set.contains(HTTP_PROTOCOL_SET)) {
00523     zret += snprintf(out+zret, n-zret, ":%s=%s", OPT_PROTO_PREFIX,TS_NPN_PROTOCOL_GROUP_HTTP);
00524     sp_set.markOut(HTTP_PROTOCOL_SET);
00525     need_colon_p = false;
00526   }
00527   if (sp_set.contains(SPDY_PROTOCOL_SET)) {
00528     if (need_colon_p) 
00529       zret += snprintf(out+zret, n-zret, ":%s=", OPT_PROTO_PREFIX);
00530     else
00531       out[zret++] = ';';
00532     zret += snprintf(out+zret, n-zret, TS_NPN_PROTOCOL_GROUP_SPDY);
00533     sp_set.markOut(SPDY_PROTOCOL_SET);
00534     need_colon_p = false;
00535   }
00536   if (sp_set.contains(HTTP2_PROTOCOL_SET)) {
00537     if (need_colon_p)
00538       zret += snprintf(out+zret, n-zret, ":%s=", OPT_PROTO_PREFIX);
00539     else
00540       out[zret++] = ';';
00541     zret += snprintf(out+zret, n-zret, "%s", TS_NPN_PROTOCOL_GROUP_HTTP2);
00542     sp_set.markOut(HTTP2_PROTOCOL_SET);
00543     need_colon_p = false;
00544   }
00545   // now enumerate what's left.
00546   if (!sp_set.isEmpty()) {
00547     if (need_colon_p)
00548       zret += snprintf(out+zret, n-zret, ":%s=", OPT_PROTO_PREFIX);
00549     bool sep_p = !need_colon_p;
00550     for ( int k = 0 ; k < SessionProtocolSet::MAX ; ++k ) {
00551       if (sp_set.contains(k)) {
00552         zret += snprintf(out+zret, n-zret, "%s%s", sep_p ? ";" : "", globalSessionProtocolNameRegistry.nameFor(k));
00553         sep_p = true;
00554       }
00555     }
00556   }
00557 
00558   return min(zret,n);
00559 }
00560 
00561 void
00562 ts_host_res_global_init()
00563 {
00564   // Global configuration values.
00565   memcpy(host_res_default_preference_order,
00566          HOST_RES_DEFAULT_PREFERENCE_ORDER,
00567          sizeof(host_res_default_preference_order));
00568 
00569   char* ip_resolve = REC_ConfigReadString("proxy.config.hostdb.ip_resolve");
00570   if (ip_resolve) {
00571     parse_host_res_preference(ip_resolve, host_res_default_preference_order);
00572   }
00573   ats_free(ip_resolve);
00574 }
00575 
00576 // Whatever executable uses librecords must call this.
00577 void
00578 ts_session_protocol_well_known_name_indices_init()
00579 {
00580   // register all the well known protocols and get the indices set.
00581   TS_NPN_PROTOCOL_INDEX_HTTP_0_9 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_0_9);
00582   TS_NPN_PROTOCOL_INDEX_HTTP_1_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_1_0);
00583   TS_NPN_PROTOCOL_INDEX_HTTP_1_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_1_1);
00584   TS_NPN_PROTOCOL_INDEX_HTTP_2_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_2_0);
00585   TS_NPN_PROTOCOL_INDEX_SPDY_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_1);
00586   TS_NPN_PROTOCOL_INDEX_SPDY_2 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_2);
00587   TS_NPN_PROTOCOL_INDEX_SPDY_3 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_3);
00588   TS_NPN_PROTOCOL_INDEX_SPDY_3_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_3_1);
00589 
00590   // Now do the predefined protocol sets.
00591   HTTP_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_0_9);
00592   HTTP_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_1_0);
00593   HTTP_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_1_1);
00594   HTTP2_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_2_0);
00595   SPDY_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_SPDY_3);
00596   SPDY_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_SPDY_3_1);
00597 
00598   DEFAULT_TLS_SESSION_PROTOCOL_SET.markAllIn();
00599   DEFAULT_NON_TLS_SESSION_PROTOCOL_SET = HTTP_PROTOCOL_SET;
00600 }
00601 
00602 SessionProtocolNameRegistry::SessionProtocolNameRegistry()
00603   : m_n(0)
00604 {
00605   memset(m_names, 0, sizeof(m_names));
00606   memset(&m_flags, 0, sizeof(m_flags));
00607 }
00608 
00609 SessionProtocolNameRegistry::~SessionProtocolNameRegistry() {
00610   for ( size_t i = 0 ; i < m_n ; ++i ) {
00611     if (m_flags[i] & F_ALLOCATED)
00612       ats_free(const_cast<char*>(m_names[i])); // blech - ats_free won't take a char const*
00613   }
00614 }
00615 
00616 int
00617 SessionProtocolNameRegistry::toIndex(char const* name) {
00618   int zret = this->indexFor(name);
00619   if (INVALID == zret) {
00620     if (m_n < static_cast<size_t>(MAX)) {
00621       m_names[m_n] = ats_strdup(name);
00622       m_flags[m_n] = F_ALLOCATED;
00623       zret = m_n++;
00624     } else {
00625       ink_release_assert(!"Session protocol name registry overflow");
00626     }
00627   }
00628   return zret;
00629 }
00630 
00631 int
00632 SessionProtocolNameRegistry::toIndexConst(char const* name) {
00633   int zret = this->indexFor(name);
00634   if (INVALID == zret) {
00635     if ( m_n < static_cast<size_t>(MAX)) {
00636       m_names[m_n] = name;
00637       zret = m_n++;
00638     } else {
00639       ink_release_assert(!"Session protocol name registry overflow");
00640     }
00641   }
00642   return zret;
00643 }
00644 
00645 int
00646 SessionProtocolNameRegistry::indexFor(char const* name) const {
00647   for ( size_t i = 0 ; i < m_n ; ++i ) {
00648     if (0 == strcasecmp(name, m_names[i]))
00649       return i;
00650   }
00651   return INVALID;
00652 }
00653 
00654 char const*
00655 SessionProtocolNameRegistry::nameFor(int idx) const {
00656   return 0 <= idx && idx < static_cast<int>(m_n)
00657     ? m_names[idx]
00658     : 0
00659     ;
00660 }

Generated by  doxygen 1.7.1