def api(path_info, repo_name, version, start_response, environ): slash = path_info.find('/') if (slash == -1): return cvmfs_api.bad_request(start_response, 'no slash in geo path') caching_string = path_info[0:slash] servers = string.split(path_info[slash + 1:], ",") # TODO(jblomer): Can this be switched to monotonic time? now = int(time.time()) gir_rem = None if caching_string.find('.'): # might be a FQDN, use it if it resolves to a geo record gir_rem = name_geoinfo(now, caching_string) if gir_rem is None: if 'HTTP_X_FORWARDED_FOR' in environ: forwarded_for = environ['HTTP_X_FORWARDED_FOR'] start = string.rfind(forwarded_for, ' ') + 1 if (start == 0): start = string.rfind(forwarded_for, ',') + 1 gir_rem = addr_geoinfo(forwarded_for[start:]) if gir_rem is None and 'REMOTE_ADDR' in environ: gir_rem = addr_geoinfo(environ['REMOTE_ADDR']) if gir_rem is None: return cvmfs_api.bad_request(start_response, 'remote addr not found in database') if '+PXYSEP+' in servers: # first geosort the proxies after the separator and if at least one # is good, sort the hosts before the separator relative to that # proxy rather than the client pxysep = servers.index('+PXYSEP+') onegood, pxyindexes = geosort_servers(now, gir_rem, servers[pxysep + 1:]) if onegood: gir_pxy = name_geoinfo(now, servers[pxysep + 1 + pxyindexes[0]]) if not gir_pxy is None: gir_rem = gir_pxy onegood, hostindexes = geosort_servers(now, gir_rem, servers[0:pxysep]) indexes = hostindexes + list(pxysep + 1 + i for i in pxyindexes) # Append the index of the separator for backward compatibility, # so the client can always expect the same number of indexes as # the number of elements in the request. indexes.append(pxysep) else: onegood, indexes = geosort_servers(now, gir_rem, servers) if not onegood: # return a bad request only if all the server names were bad return cvmfs_api.bad_request(start_response, 'no server addr found in database') response_body = string.join((str(i + 1) for i in indexes), ',') + '\n' status = '200 OK' response_headers = [('Content-Type', 'text/plain'), ('Cache-Control', 'max-age=' + str(positive_expire_secs)), ('Content-Length', str(len(response_body)))] start_response(status, response_headers) return [response_body]
def api(path_info, repo_name, version, start_response, environ): start = string.find(path_info, '/') + 1 if (start == 0): return cvmfs_api.bad_request(start_response, 'no slash in geo path') servers = string.split(path_info[start:], ",") rem_addr = '' if 'HTTP_X_FORWARDED_FOR' in environ: forwarded_for = environ['HTTP_X_FORWARDED_FOR'] start = string.rfind(forwarded_for, ' ') + 1 if (start == 0): start = string.rfind(forwarded_for, ',') + 1 rem_addr = forwarded_for[start:] else: if 'REMOTE_ADDR' in environ: rem_addr = environ['REMOTE_ADDR'] if (len(rem_addr) < 256) and addr_pattern.search(rem_addr): gir_rem = gi.record_by_addr(rem_addr) else: gir_rem = None if gir_rem is None: return cvmfs_api.bad_request(start_response, 'remote addr not found in database') idx = 1 arcs = [] indexes = [] onegood = False for server in servers: if (len(server) < 256) and addr_pattern.search(server): gir_server = gi.record_by_name(server) else: gir_server = None if gir_server is None: # put it on the end of the list arc = float("inf") else: onegood = True arc = distance_on_unit_sphere(gir_rem['latitude'], gir_rem['longitude'], gir_server['latitude'], gir_server['longitude']) i = bisect.bisect(arcs, arc) arcs[i:i] = [ arc ] indexes[i:i] = [ str(idx) ] idx += 1 if not onegood: # return a bad request only if all the server names were bad return cvmfs_api.bad_request(start_response, 'no server addr found in database') response_body = string.join(indexes, ',') + '\n' status = '200 OK' response_headers = [('Content-Type', 'text/plain'), ('Cache-Control', 'max-age=' + str(positive_expire_secs)), ('Content-Length', str(len(response_body)))] start_response(status, response_headers) return [response_body]
def api(path_info, repo_name, version, start_response, environ): slash = path_info.find('/') if (slash == -1): return cvmfs_api.bad_request(start_response, 'no slash in geo path') caching_string = path_info[0:slash] servers = string.split(path_info[slash+1:], ",") # TODO(jblomer): Can this be switched to monotonic time? now = int(time.time()) gir_rem = None if caching_string.find('.'): # might be a FQDN, use it if it resolves to a geo record gir_rem = name_geoinfo(now, caching_string) trycdn = False if gir_rem is None: if 'HTTP_CF_CONNECTING_IP' in environ: # IP address of client connecting to Cloudflare gir_rem = addr_geoinfo(environ['HTTP_CF_CONNECTING_IP']) if gir_rem is not None: # Servers probably using Cloudflare Content Delivery Network too trycdn = True if gir_rem is None and 'HTTP_X_FORWARDED_FOR' in environ: # List of IP addresses forwarded through squid # Try the last IP, in case there's a reverse proxy squid # in front of the web server. forwarded_for = environ['HTTP_X_FORWARDED_FOR'] start = string.rfind(forwarded_for, ' ') + 1 if (start == 0): start = string.rfind(forwarded_for, ',') + 1 gir_rem = addr_geoinfo(forwarded_for[start:]) if gir_rem is None and 'REMOTE_ADDR' in environ: # IP address connecting to web server gir_rem = addr_geoinfo(environ['REMOTE_ADDR']) if gir_rem is None: return cvmfs_api.bad_request(start_response, 'remote addr not found in database') if '+PXYSEP+' in servers: # first geosort the proxies after the separator and if at least one # is good, sort the hosts before the separator relative to that # proxy rather than the client pxysep = servers.index('+PXYSEP+') # assume backup proxies will not be behind a CDN onegood, pxyindexes = \ geosort_servers(now, gir_rem, servers[pxysep+1:], False) if onegood: gir_pxy = name_geoinfo(now, servers[pxysep+1+pxyindexes[0]]) if not gir_pxy is None: gir_rem = gir_pxy onegood, hostindexes = \ geosort_servers(now, gir_rem, servers[0:pxysep], trycdn) indexes = hostindexes + list(pxysep+1+i for i in pxyindexes) # Append the index of the separator for backward compatibility, # so the client can always expect the same number of indexes as # the number of elements in the request. indexes.append(pxysep) else: onegood, indexes = geosort_servers(now, gir_rem, servers, trycdn) if not onegood: # return a bad request only if all the server names were bad return cvmfs_api.bad_request(start_response, 'no server addr found in database') response_body = string.join((str(i+1) for i in indexes), ',') + '\n' status = '200 OK' response_headers = [('Content-Type', 'text/plain'), ('Cache-Control', 'max-age=' + str(positive_expire_secs)), ('Content-Length', str(len(response_body)))] start_response(status, response_headers) return [response_body]
def api(path_info, repo_name, version, start_response, environ): slash = path_info.find('/') if (slash == -1): return cvmfs_api.bad_request(start_response, 'no slash in geo path') caching_string = path_info[0:slash] servers = string.split(path_info[slash+1:], ",") if caching_string == "_namelookups_": # this is a special debugging URL return cvmfs_api.good_request(start_response, str(namelookups) + '\n') # TODO(jblomer): Can this be switched to monotonic time? now = int(time.time()) trycdn = False if 'HTTP_CF_CONNECTING_IP' in environ: # Request is coming from Cloudflare Content Delivery Network; # servers are probably using Cloudflare too. trycdn = True gir_rem = None if caching_string.find('.'): # might be a FQDN, use it if it resolves to a geo record gir_rem = name_geoinfo(now, caching_string) if gir_rem is None: if 'HTTP_CF_CONNECTING_IP' in environ: # IP address of client connecting to Cloudflare gir_rem = addr_geoinfo(now, environ['HTTP_CF_CONNECTING_IP']) if gir_rem is None and 'HTTP_X_FORWARDED_FOR' in environ: # List of IP addresses forwarded through squid # Try the last IP, in case there's a reverse proxy squid # in front of the web server. forwarded_for = environ['HTTP_X_FORWARDED_FOR'] start = string.rfind(forwarded_for, ' ') + 1 if (start == 0): start = string.rfind(forwarded_for, ',') + 1 gir_rem = addr_geoinfo(now, forwarded_for[start:]) if gir_rem is None and 'REMOTE_ADDR' in environ: # IP address connecting to web server gir_rem = addr_geoinfo(now, environ['REMOTE_ADDR']) if gir_rem is None: return cvmfs_api.bad_request(start_response, 'remote addr not found in database') if '+PXYSEP+' in servers: # first geosort the proxies after the separator and if at least one # is good, sort the hosts before the separator relative to that # proxy rather than the client pxysep = servers.index('+PXYSEP+') # assume backup proxies will not be behind a CDN onegood, pxyindexes = \ geosort_servers(now, gir_rem, servers[pxysep+1:], False) if onegood: gir_pxy = name_geoinfo(now, servers[pxysep+1+pxyindexes[0]]) if not gir_pxy is None: gir_rem = gir_pxy onegood, hostindexes = \ geosort_servers(now, gir_rem, servers[0:pxysep], trycdn) indexes = hostindexes + list(pxysep+1+i for i in pxyindexes) # Append the index of the separator for backward compatibility, # so the client can always expect the same number of indexes as # the number of elements in the request. indexes.append(pxysep) else: onegood, indexes = geosort_servers(now, gir_rem, servers, trycdn) if not onegood: # return a bad request only if all the server names were bad return cvmfs_api.bad_request(start_response, 'no server addr found in database') response_body = string.join((str(i+1) for i in indexes), ',') + '\n' return cvmfs_api.good_request(start_response, response_body)
def api(path_info, repo_name, version, start_response, environ): slash = path_info.find('/') if (slash == -1): return cvmfs_api.bad_request(start_response, 'no slash in geo path') caching_string = path_info[0:slash] servers = string.split(path_info[slash+1:], ",") gir_rem = None rem_addr = '' if caching_string.find('.'): # might be a FQDN, use it if it resolves to an address try: ai = socket.getaddrinfo(caching_string,80,0,0,socket.IPPROTO_TCP) arec = ai[0] # prefer IPv4 because the database is more accurate for info in ai: if info[0] == socket.AF_INET: arec = info break rem_addr = arec[4][0] except: pass else: gir_rem = addr_geoinfo(rem_addr) if gir_rem is None: rem_addr = '' if 'HTTP_X_FORWARDED_FOR' in environ: forwarded_for = environ['HTTP_X_FORWARDED_FOR'] start = string.rfind(forwarded_for, ' ') + 1 if (start == 0): start = string.rfind(forwarded_for, ',') + 1 rem_addr = forwarded_for[start:] else: if 'REMOTE_ADDR' in environ: rem_addr = environ['REMOTE_ADDR'] if (len(rem_addr) < 256) and addr_pattern.search(rem_addr): gir_rem = addr_geoinfo(rem_addr) if gir_rem is None: return cvmfs_api.bad_request(start_response, 'remote addr not found in database') idx = 1 arcs = [] indexes = [] onegood = False for server in servers: if (len(server) < 256) and addr_pattern.search(server): # try IPv4 first since that DB is better and most servers # today are dual stack if they have IPv6 gir_server = gi.record_by_name(server) if gir_server is None: gir_server = gi6.record_by_name_v6(server) else: gir_server = None if gir_server is None: # put it on the end of the list arc = float("inf") else: onegood = True arc = distance_on_unit_sphere(gir_rem['latitude'], gir_rem['longitude'], gir_server['latitude'], gir_server['longitude']) #print "distance between " + \ # rem_addr + ' (' + str(gir_rem['latitude']) + ',' + str(gir_rem['longitude']) + ')' \ # + " and " + \ # server + ' (' + str(gir_server['latitude']) + ',' + str(gir_server['longitude']) + ')' + \ # " is " + str(arc) i = bisect.bisect(arcs, arc) arcs[i:i] = [ arc ] indexes[i:i] = [ str(idx) ] idx += 1 if not onegood: # return a bad request only if all the server names were bad return cvmfs_api.bad_request(start_response, 'no server addr found in database') response_body = string.join(indexes, ',') + '\n' status = '200 OK' response_headers = [('Content-Type', 'text/plain'), ('Cache-Control', 'max-age=' + str(positive_expire_secs)), ('Content-Length', str(len(response_body)))] start_response(status, response_headers) return [response_body]