diff --git a/confluent_server/confluent/discovery/protocols/pxe.py b/confluent_server/confluent/discovery/protocols/pxe.py index 11922793..5cb9a43c 100644 --- a/confluent_server/confluent/discovery/protocols/pxe.py +++ b/confluent_server/confluent/discovery/protocols/pxe.py @@ -169,14 +169,18 @@ pxearchs = { shorturls = {} -def register_shorturl(url): +urlidbyurl = {} +def register_shorturl(url, can302=True, relurl=None, filename=None): + if url in urlidbyurl: + return urlidbyurl[url] urlid = base64.urlsafe_b64encode(os.urandom(3)) while urlid in shorturls: urlid = base64.urlsafe_b64encode(os.urandom(3)) urlid = urlid.decode() - shorturls[urlid] = url + shorturls[urlid] = (url, can302, relurl, filename) returl = '/'.join(url.split('/')[:3]) returl += '/confluent-api/boot/su/' + urlid + '/' + os.path.basename(url) + urlidbyurl[url] = returl return returl @@ -830,16 +834,20 @@ def reply_dhcp4(node, info, packet, cfg, reqview, httpboot, cfd, profile, sock=N if niccfg['ipv4_address'] == myipn: log.log({'error': 'Unable to serve {0} due to duplicated address between node and interface index "{}"'.format(node, info['netinfo']['ifidx'])}) return + can302 = True if httpboot: proto = 'https' if insecuremode == 'never' else 'http' bootfile = '{0}://{1}/confluent-public/os/{2}/boot.img'.format( proto, myipn, profile ) + bootshorturl = '/confluent-public/os/{0}/boot.img'.format(profile) + bootfilename = '/var/lib/confluent/public/os/{0}/boot.img'.format(profile) + can302 = False if not isinstance(bootfile, bytes): bootfile = bootfile.encode('utf8') if len(bootfile) > 127: if bootfile.startswith(b'http'): - bootfile = register_shorturl(bootfile.decode('utf8')).encode('utf8') + bootfile = register_shorturl(bootfile.decode('utf8'), can302, bootshorturl, bootfilename).encode('utf8') else: log.log( {'info': 'Boot offer cannot be made to {0} as the ' diff --git a/confluent_server/confluent/httpapi.py b/confluent_server/confluent/httpapi.py index 97909710..db521cc1 100644 --- a/confluent_server/confluent/httpapi.py +++ b/confluent_server/confluent/httpapi.py @@ -684,14 +684,26 @@ def resourcehandler_backend(env, start_response): if not request[0]: request = request[1:] if request[1] == 'su': # shorturl - targurl = pxe.shorturls.get(request[2], None) + targurl, can302, relurl, bootfilename = pxe.shorturls.get(request[2], (None, None, None, None)) if not targurl: start_response('404 Not Found', headers) yield '' return - headers.append(('Location', targurl)) - start_response('302 Found', headers) - yield '' + if can302: # Maximum transparency helps iPXE and whatever else know the most + headers.append(('Location', targurl)) + start_response('302 Found', headers) + yield '' + else: # The user agent is too dumb, check headers for server side redirects + delegatemethod = env.get('HTTP_X_DELEGATE_METHOD', None) + if delegatemethod == 'accel': + headers = [('Content-Type', 'application/octet-stream')] + headers.append(('X-Accel-Redirect', relurl)) + start_response('200 OK', headers) + yield '' + else: + start_response('502 Bad Gateway', headers) + yield 'URL shortening for a limited client without proxy advertised accel support' + log.log({'error': f'Profile name exceeded DHCP limits, and reverse proxy capabilities not detected, switch to the nginx configuration or shorten the profile name: {relurl}'}) return if len(request) != 4: start_response('400 Bad Request', headers)