Esempio n. 1
0
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]
Esempio n. 2
0
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]
Esempio n. 3
0
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]
Esempio n. 4
0
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)
Esempio n. 5
0
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]