Esempio n. 1
0
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)
Esempio n. 2
0
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