def octoprint_http_tunnel(request, pk): # We need to catch the moment when tunnel page loads, # and redirect to v2 url if plugin version is compatible. if request.path == tunnel_views.URL_PREFIX.format(pk=pk) + '/': get_printer_or_404(pk, request) version = (cache.printer_settings_get(pk) or {}).get('tsd_plugin_version', '') if tunnelv2_views.is_plugin_version_supported(version): return tunnelv2_views.redirect_to_tunnel_url(request, pk) return tunnel_views.octoprint_http_tunnel(request, pk)
def tunnel(request, pk, template_dir=None): get_printer_or_404(pk, request) version = (cache.printer_settings_get(pk) or {}).get('tsd_plugin_version', '') is_v1 = version and not is_plugin_version_supported(version) return render( request, get_template_path('tunnel', template_dir), {"v1": is_v1}, )
def settings(self): p_settings = cache.printer_settings_get(self.id) for key in ('webcam_flipV', 'webcam_flipH', 'webcam_rotate90'): p_settings[key] = p_settings.get(key, 'False') == 'True' p_settings['ratio169'] = p_settings.get('webcam_streamRatio', '4:3') == '16:9' if p_settings.get('temp_profiles'): p_settings['temp_profiles'] = json.loads(p_settings.get('temp_profiles')) return p_settings
def _octoprint_http_tunnel(request, octoprinttunnel): user = octoprinttunnel.printer.user if user.tunnel_usage_over_cap(): return HttpResponse(OVER_FREE_LIMIT_HTML, status=OVER_FREE_LIMIT_STATUS_CODE) # if plugin is disconnected, halt if channels.num_ws_connections( channels.octo_group_name(octoprinttunnel.printer.id)) < 1: return HttpResponse(NOT_CONNECTED_HTML, status=NOT_CONNECTED_STATUS_CODE) version = (cache.printer_settings_get(octoprinttunnel.printer.pk) or {}).get('tsd_plugin_version', '') is_v1 = version and not is_plugin_version_supported(version) if is_v1: return HttpResponse(NOT_CONNECTED_HTML, status=NOT_CONNECTED_STATUS_CODE) method = request.method.lower() path = request.get_full_path() IGNORE_HEADERS = [ 'HTTP_HOST', 'HTTP_ORIGIN', 'HTTP_REFERER', # better not to tell 'HTTP_AUTHORIZATION', # handled explicitely 'HTTP_COOKIE', # handled explicitely 'HTTP_ACCEPT_ENCODING', # should be handled by TSD server ] req_headers = { k[5:].replace('_', ' ').title().replace(' ', '-'): v for (k, v) in request.META.items() if (k.startswith('HTTP') and k not in IGNORE_HEADERS and not k.startswith('HTTP_X_FORWARDED') # meant for TSD server ) } if 'CONTENT_TYPE' in request.META: req_headers['Content-Type'] = request.META['CONTENT_TYPE'] if 'HTTP_COOKIE' in request.META: # let's not forward cookies of TSD server stripped_cookies = '; '.join([ cookie.strip() for cookie in request.META['HTTP_COOKIE'].split(';') if DJANGO_COOKIE_RE.match(cookie.strip()) is None ]) if stripped_cookies: req_headers['Cookie'] = stripped_cookies if hasattr(request, 'auth_header'): # let's not forward basic auth header of external tunnel stripped_auth_heaader = ', '.join([ h for h in request.META['HTTP_AUTHORIZATION'].split(',') if h != request.auth_header ]) if stripped_auth_heaader: req_headers['Authorization'] = stripped_auth_heaader ref = f'v2.{octoprinttunnel.id}.{method}.{time.time()}.{path}' channels.send_msg_to_printer( octoprinttunnel.printer.id, { 'http.tunnelv2': { 'ref': ref, 'method': method, 'headers': req_headers, 'path': path, 'data': request.body }, 'as_binary': True, }) data = cache.octoprinttunnel_http_response_get(ref) if data is None: # request timed out return HttpResponse(NOT_CONNECTED_HTML, status=TIMED_OUT_STATUS_CODE) content_type = data['response']['headers'].get('Content-Type') or None status_code = data['response']['status'] resp = HttpResponse( status=status_code, content_type=content_type, ) to_ignore = ( 'content-length', # set by django 'content-encoding', # if its set, it is probably incorrect/unapplicable 'x-frame-options', # response must load in TSD's iframe ) for k, v in data['response']['headers'].items(): if k.lower() in to_ignore: continue if k.lower() == 'etag': # pre 1.6.? octoprint has invalid etag format for some responses v = fix_etag(v) resp[k] = v # plugin connects over http to octoprint, # but TSD needs cookies working over https. # without this, cookies set in response might not be used # in some browsers (FF gives wwarning) for cookie in (data['response'].get('cookies', ()) or ()): if (request.is_secure() and 'secure' not in cookie.lower()): cookie += '; Secure' if 'Expires=' not in cookie and 'Max-Age=' not in cookie: cookie += '; Max-Age=7776000' # 3 months resp['Set-Cookie'] = cookie if data['response'].get('compressed', False): content = zlib.decompress(data['response']['content']) else: content = data['response']['content'] cache.octoprinttunnel_update_stats(user.id, len(content)) resp.write(content) return resp