def read(self, request, vendor, name, version): operator = get_object_or_404(CatalogueResource, type=2, vendor=vendor, short_name=name, version=version) # For now, all operators are freely accessible/distributable # if not operator.is_available_for(request.user): # return HttpResponseForbidden() mode = request.GET.get('mode', 'classic') key = get_operator_cache_key(operator, get_current_domain(request), mode) cached_response = cache.get(key) if cached_response is None: options = operator.json_description js_files = options['js_files'] base_url = get_absolute_reverse_url('wirecloud.showcase_media', kwargs={ 'vendor': operator.vendor, 'name': operator.short_name, 'version': operator.version, 'file_path': operator.template_uri }, request=request) xhtml = generate_xhtml_operator_code(js_files, base_url, request, process_requirements(options['requirements']), mode) cache_timeout = 31536000 # 1 year cached_response = CacheableData(xhtml, timeout=cache_timeout, content_type='application/xhtml+xml; charset=UTF-8') cache.set(key, cached_response, cache_timeout) return cached_response.get_response()
def get_widget_api_files(request): from wirecloud.platform.core.plugins import get_version_hash key = 'widget_api_files/%s?v=%s' % (get_current_domain(request), get_version_hash()) widget_api_files = cache.get(key) if widget_api_files is None or settings.DEBUG is True: code = '''{% load compress %}{% load static from staticfiles %}{% compress js %} <script type="text/javascript" src="{% static "js/WirecloudAPI/WirecloudAPIBootstrap.js" %}"></script> <script type="text/javascript" src="{% static "js/WirecloudAPI/WirecloudWidgetAPI.js" %}"></script> <script type="text/javascript" src="{% static "js/WirecloudAPI/WirecloudAPICommon.js" %}"></script> {% endcompress %}''' result = Template(code).render(Context()) doc = etree.parse( BytesIO(('<files>' + result + '</files>').encode('utf-8')), etree.XMLParser()) files = [script.get('src') for script in doc.getroot()] files.reverse() widget_api_files = tuple([ get_absolute_static_url(file, request=request, versioned=True) for file in files ]) cache.set(key, widget_api_files) return list(widget_api_files)
def test_get_current_domain_forced(self): request = self._prepare_request_mock() with patch(self.get_current_site_import) as get_current_site_mock: with patch.multiple('wirecloud.commons.utils.http', socket=DEFAULT, get_current_scheme=DEFAULT) as mocks: mocks['get_current_scheme'].return_value = 'http' self.assertEqual(get_current_domain(request), 'myserver.com:8080') self.assertEqual(mocks['socket'].getfqdn.call_count, 0) self.assertEqual(get_current_site_mock.call_count, 0)
def test_get_current_domain_forced_port(self): request = self._prepare_request_mock() with patch('django.contrib.sites.shortcuts.get_current_site') as get_current_site_mock: with patch.multiple('wirecloud.commons.utils.http', socket=DEFAULT, get_current_scheme=DEFAULT, _servername=None) as mocks: get_current_site_mock.return_value = self._prepare_site_mock() mocks['get_current_scheme'].return_value = 'http' self.assertEqual(get_current_domain(request), 'site.example.com:81') self.assertEqual(mocks['socket'].getfqdn.call_count, 0)
def test_get_current_domain_fallback_https_custom_port(self): request = self._prepare_request_mock() with patch('django.contrib.sites.models.get_current_site') as get_current_site_mock: with patch.multiple('wirecloud.commons.utils.http', socket=DEFAULT, get_current_scheme=DEFAULT) as mocks: get_current_site_mock.side_effect = Exception mocks['socket'].getfqdn.return_value = 'example.com' mocks['get_current_scheme'].return_value = 'http' self.assertEqual(get_current_domain(request), 'fqdn.example.com:8443')
def test_get_current_domain_fallback_https_custom_port(self): request = self._prepare_request_mock() with patch('django.contrib.sites.shortcuts.get_current_site') as get_current_site_mock: with patch.multiple('wirecloud.commons.utils.http', socket=DEFAULT, get_current_scheme=DEFAULT, _servername=None) as mocks: get_current_site_mock.side_effect = Exception mocks['socket'].getfqdn.return_value = 'example.com' mocks['get_current_scheme'].return_value = 'http' self.assertEqual(get_current_domain(request), 'example.com:8443')
def test_get_current_domain_forced_port(self): request = self._prepare_request_mock() with patch('django.contrib.sites.models.get_current_site') as get_current_site_mock: with patch.multiple('wirecloud.commons.utils.http', socket=DEFAULT, get_current_scheme=DEFAULT) as mocks: get_current_site_mock.return_value = self._prepare_site_mock() mocks['get_current_scheme'].return_value = 'http' self.assertEqual(get_current_domain(request), 'site.example.com:81') self.assertEqual(mocks['socket'].getfqdn.call_count, 0)
def test_get_current_domain_fallback_https(self): request = self._prepare_request_mock() with patch(self.get_current_site_import) as get_current_site_mock: with patch.multiple('wirecloud.commons.utils.http', socket=DEFAULT, get_current_scheme=DEFAULT) as mocks: get_current_site_mock.side_effect = Exception mocks['socket'].getfqdn.return_value = 'fqdn.example.com' mocks['get_current_scheme'].return_value = 'https' self.assertEqual(get_current_domain(request), 'fqdn.example.com')
def test_get_current_domain_forced_domain(self): request = self._prepare_request_mock() with patch(self.get_current_site_import) as get_current_site_mock: with patch.multiple('wirecloud.commons.utils.http', socket=DEFAULT, get_current_scheme=DEFAULT) as mocks: get_current_site_mock.return_value = self._prepare_site_mock() mocks['get_current_scheme'].return_value = 'http' self.assertEqual(get_current_domain(request), 'forced.example.com:8000') self.assertEqual(mocks['socket'].getfqdn.call_count, 0)
def test_get_current_domain_forced(self): request = self._prepare_request_mock() with patch('django.contrib.sites.models.get_current_site' ) as get_current_site_mock: with patch.multiple('wirecloud.commons.utils.http', socket=DEFAULT, get_current_scheme=DEFAULT) as mocks: mocks['get_current_scheme'].return_value = 'http' self.assertEqual(get_current_domain(request), 'myserver.com:8080') self.assertEqual(mocks['socket'].getfqdn.call_count, 0) self.assertEqual(get_current_site_mock.call_count, 0)
def read(self, request, vendor, name, version): widget = get_object_or_404( Widget, resource__vendor=vendor, resource__short_name=name, resource__version=version ) if not widget.is_available_for(request.user): raise Http403() # check if the xhtml code has been cached if widget.xhtml.cacheable: cache_key = widget.xhtml.get_cache_key(get_current_domain(request)) cache_entry = cache.get(cache_key) if cache_entry is not None: response = HttpResponse(cache_entry["code"], mimetype="%s; charset=UTF-8" % cache_entry["content_type"]) patch_cache_headers(response, cache_entry["timestamp"], cache_entry["timeout"]) return response # process xhtml xhtml = widget.xhtml content_type = xhtml.content_type if not content_type: content_type = "text/html" force_base = False base_url = xhtml.url if not base_url.startswith(("http://", "https://")): base_url = get_absolute_reverse_url( "wirecloud_showcase.media", args=(base_url.split("/", 4)), request=request ) force_base = True code = xhtml.code if not xhtml.cacheable or code == "": try: if xhtml.url.startswith(("http://", "https://")): code = downloader.download_http_content(urljoin(base_url, xhtml.url), user=request.user) else: code = downloader.download_http_content( "file://" + os.path.join(showcase_utils.wgt_deployer.root_dir, xhtml.url), user=request.user ) except Exception, e: # FIXME: Send the error or use the cached original code? msg = _("XHTML code is not accessible: %(errorMsg)s") % {"errorMsg": e.message} return HttpResponse(get_xml_error_response(msg), mimetype="application/xml; charset=UTF-8")
def read(self, request, vendor, name, version): operator = get_object_or_404(CatalogueResource, type=2, vendor=vendor, short_name=name, version=version) # For now, all operators are freely accessible/distributable #if not operator.is_available_for(request.user): # return HttpResponseForbidden() mode = request.GET.get('mode', 'classic') key = get_operator_cache_key(operator, get_current_domain(request), mode) cached_response = cache.get(key) if cached_response is None: options = json.loads(operator.json_description) js_files = options['js_files'] base_url = operator.template_uri if not base_url.startswith(('http://', 'https://')): base_url = get_absolute_reverse_url('wirecloud.showcase_media', kwargs={ 'vendor': operator.vendor, 'name': operator.short_name, 'version': operator.version, 'file_path': operator.template_uri }, request=request) xhtml = generate_xhtml_operator_code( js_files, base_url, request, process_requirements(options['requirements']), mode) cache_timeout = 31536000 # 1 year cached_response = CacheableData( xhtml, timeout=cache_timeout, content_type='application/xhtml+xml; charset=UTF-8') cache.set(key, cached_response, cache_timeout) return cached_response.get_response()
def read(self, request, vendor, name, version): resource = get_object_or_404(CatalogueResource.objects.select_related('widget__xhtml'), vendor=vendor, short_name=name, version=version) if not resource.is_available_for(request.user): raise Http403() if resource.resource_type() != 'widget': raise Http404() widget_info = json.loads(resource.json_description) # check if the xhtml code has been cached if widget_info['code_cacheable'] is True: cache_key = resource.widget.xhtml.get_cache_key(get_current_domain(request)) cache_entry = cache.get(cache_key) if cache_entry is not None: response = HttpResponse(cache_entry['code'], mimetype=cache_entry['mimetype']) patch_cache_headers(response, cache_entry['timestamp'], cache_entry['timeout']) return response # process xhtml xhtml = resource.widget.xhtml content_type = widget_info.get('code_content_type', 'text/html') charset = widget_info.get('code_charset', 'utf-8') force_base = False base_url = xhtml.url if not base_url.startswith(('http://', 'https://')): base_url = get_absolute_reverse_url('wirecloud_showcase.media', args=(base_url.split('/', 4)), request=request) force_base = True code = xhtml.code if not xhtml.cacheable or code == '': try: if xhtml.url.startswith(('http://', 'https://')): code = downloader.download_http_content(urljoin(base_url, xhtml.url), user=request.user) else: code = downloader.download_http_content('file://' + os.path.join(showcase_utils.wgt_deployer.root_dir, url2pathname(xhtml.url)), user=request.user) except Exception, e: msg = _("XHTML code is not accessible: %(errorMsg)s") % {'errorMsg': e.message} return build_error_response(request, 502, msg)
def get_widget_api_files(request): from wirecloud.platform.core.plugins import get_version_hash key = 'widget_api_files/%s?v=%s' % (get_current_domain(request), get_version_hash()) widget_api_files = cache.get(key) if widget_api_files is None or settings.DEBUG is True: code = '''{% load compress %}{% load static from staticfiles %}{% compress js %} <script type="text/javascript" src="{% static "js/WirecloudAPI/WirecloudAPIBootstrap.js" %}"></script> <script type="text/javascript" src="{% static "js/WirecloudAPI/WirecloudWidgetAPI.js" %}"></script> <script type="text/javascript" src="{% static "js/WirecloudAPI/WirecloudAPICommon.js" %}"></script> {% endcompress %}''' result = Template(code).render(Context({})) doc = etree.parse(BytesIO(('<files>' + result + '</files>').encode('utf-8')), etree.XMLParser()) files = [script.get('src') for script in doc.getroot()] files.reverse() widget_api_files = tuple([get_absolute_static_url(file, request=request, versioned=True) for file in files]) cache.set(key, widget_api_files) return list(widget_api_files)
def do_request(self, request, url, method, request_data): url = iri_to_uri(url) request_data.update({ "method": method, "url": url, "original-request": request, }) request_data.setdefault("data", None) request_data.setdefault("headers", {}) request_data.setdefault("cookies", SimpleCookie()) request_data.setdefault("user", request.user) # Request creation proto, host, cgi, param, query = urlparse(url)[:5] # Build the Via header protocolVersion = self.protocolRE.match(request.META['SERVER_PROTOCOL']) if protocolVersion is not None: protocolVersion = protocolVersion.group(1) else: protocolVersion = '1.1' via_header = "%s %s (Wirecloud-python-Proxy/1.1)" % (protocolVersion, get_current_domain(request)) if 'via' in request_data['headers']: request_data['headers']['via'] += ', ' + via_header else: request_data['headers']['via'] = via_header # XFF headers if 'x-forwarded-for' in request_data['headers']: request_data['headers']['x-forwarded-for'] += ', ' + request.META['REMOTE_ADDR'] else: request_data['headers']['x-forwarded-for'] = request.META['REMOTE_ADDR'] # Pass proxy processors to the new request try: for processor in get_request_proxy_processors(): processor.process_request(request_data) except ValidationError as e: return e.get_response(request) # Cookies cookie_header_content = ', '.join([request_data['cookies'][key].OutputString() for key in request_data['cookies']]) if cookie_header_content != '': request_data['headers']['Cookie'] = cookie_header_content # Seems that Django or WSGI provides default values for the # Content-Length and Content-Type headers, so we are not able to detect # if the request provided them :( if str(request_data['headers'].get('content-length', '0')).strip() == '0': request_data['data'] = None if 'content-type' in request_data['headers']: del request_data['headers']['content-type'] # Open the request try: res = requests.request(request_data['method'], request_data['url'], headers=request_data['headers'], data=request_data['data'], stream=True, verify=getattr(settings, 'WIRECLOUD_HTTPS_VERIFY', True)) except requests.exceptions.Timeout as e: return build_error_response(request, 504, _('Gateway Timeout'), details=six.text_type(e)) except requests.exceptions.SSLError as e: return build_error_response(request, 502, _('SSL Error'), details=six.text_type(e)) except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError, requests.exceptions.TooManyRedirects) as e: return build_error_response(request, 504, _('Connection Error'), details=six.text_type(e)) # Build a Django response response = StreamingHttpResponse(res.raw.stream(4096, decode_content=False), status=res.status_code, reason=res.reason) # Add all the headers received from the response for header in res.headers: header_lower = header.lower() if header_lower == 'set-cookie': for cookie in res.cookies: response.set_cookie(cookie.name, value=cookie.value, expires=cookie.expires, path=cookie.path) elif header_lower == 'via': via_header = via_header + ', ' + res.headers[header] elif is_valid_response_header(header_lower): response[header] = res.headers[header] # Pass proxy processors to the response for processor in get_response_proxy_processors(): response = processor.process_response(request_data, response) response['Via'] = via_header return response
def do_request(self, request, url, method, workspace): url = iri_to_uri(url) request_data = { "method": method, "url": url, "data": None, "headers": {}, "cookies": SimpleCookie(), "user": request.user, "workspace": workspace, "original-request": request, } # Request creation proto, host, cgi, param, query = urlparse(url)[:5] # Extract headers from META if 'HTTP_TRANSFER_ENCODING' in request.META: return build_error_response( request, 422, "Wirecloud doesn't support requests using the Transfer-Encoding header" ) for header in request.META.items(): header_name = header[0].lower() if header_name == 'content_type' and header[1]: request_data['headers']["content-type"] = header[1] elif header_name == 'content_length' and header[1]: # Only take into account request body if the request has a # Content-Length header (we don't support chunked requests) request_data['data'] = request request_data['headers']['content-length'] = header[1] request_data['data'].len = int(header[1]) elif header_name == 'cookie' or header_name == 'http_cookie': cookie_parser = SimpleCookie(str(header[1])) del cookie_parser[str(settings.SESSION_COOKIE_NAME)] if str(settings.CSRF_COOKIE_NAME) in cookie_parser: del cookie_parser[str(settings.CSRF_COOKIE_NAME)] request_data['cookies'].update(cookie_parser) elif self.http_headerRE.match( header_name ) and not header_name in self.blacklisted_http_headers: fixed_name = header_name.replace("http_", "", 1).replace('_', '-') request_data['headers'][fixed_name] = header[1] # Build the Via header protocolVersion = self.protocolRE.match( request.META['SERVER_PROTOCOL']) if protocolVersion is not None: protocolVersion = protocolVersion.group(1) else: protocolVersion = '1.1' via_header = "%s %s (Wirecloud-python-Proxy/1.1)" % ( protocolVersion, get_current_domain(request)) if 'via' in request_data['headers']: request_data['headers']['via'] += ', ' + via_header else: request_data['headers']['via'] = via_header # XFF headers if 'x-forwarded-for' in request_data['headers']: request_data['headers'][ 'x-forwarded-for'] += ', ' + request.META['REMOTE_ADDR'] else: request_data['headers']['x-forwarded-for'] = request.META[ 'REMOTE_ADDR'] request_data['headers']['x-forwarded-host'] = host if 'x-forwarded-server' in request_data['headers']: del request_data['headers']['x-forwarded-server'] # Pass proxy processors to the new request try: for processor in get_request_proxy_processors(): processor.process_request(request_data) except ValidationError as e: return e.get_response(request) # Cookies cookie_header_content = ', '.join([ cookie_parser[key].OutputString() for key in request_data['cookies'] ]) if cookie_header_content != '': request_data['headers']['Cookie'] = cookie_header_content # Open the request try: res = requests.request(request_data['method'], request_data['url'], headers=request_data['headers'], data=request_data['data'], stream=True, verify=getattr(settings, 'WIRECLOUD_HTTPS_VERIFY', True)) except requests.exceptions.Timeout as e: return build_error_response(request, 504, _('Gateway Timeout'), details=six.text_type(e)) except requests.exceptions.SSLError as e: return build_error_response(request, 502, _('SSL Error'), details=six.text_type(e)) except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError, requests.exceptions.TooManyRedirects) as e: return build_error_response(request, 504, _('Connection Error'), details=six.text_type(e)) # Build a Django response response = StreamingHttpResponse(res.raw.stream(4096, decode_content=False), status=res.status_code) if 'reason_phrase' in response: # pragma: no cover # Currently only django 1.6+ supports custom reason phrases response.reason_phrase = res.reason_phrase # Add all the headers received from the response for header in res.headers: header_lower = header.lower() if header_lower == 'set-cookie': for cookie in res.cookies: response.set_cookie(cookie.name, value=cookie.value, expires=cookie.expires, path=cookie.path) elif header_lower == 'via': via_header = via_header + ', ' + res.headers[header] elif is_valid_response_header(header_lower): response[header] = res.headers[header] # Pass proxy processors to the response for processor in get_response_proxy_processors(): response = processor.process_response(request_data, response) response['Via'] = via_header return response
def do_request(self, request, url, method, workspace): url = iri_to_uri(url) request_data = { "method": method, "url": url, "data": None, "headers": {}, "cookies": SimpleCookie(), "user": request.user, "workspace": workspace, "original-request": request, } # Request creation proto, host, cgi, param, query = urlparse(url)[:5] # Extract headers from META if 'HTTP_TRANSFER_ENCODING' in request.META: return build_error_response(request, 500, "Wirecloud doesn't support requests using Transfer-Encodings") for header in request.META.items(): header_name = header[0].lower() if header_name == 'content_type' and header[1]: request_data['headers']["content-type"] = header[1] elif header_name == 'content_length' and header[1]: # Only take into account request body if the request has a # Content-Length header (we don't support chunked requests) request_data['data'] = request request_data['headers']['content-length'] = header[1] request_data['data'].len = int(header[1]) elif header_name == 'cookie' or header_name == 'http_cookie': cookie_parser = SimpleCookie(str(header[1])) del cookie_parser[str(settings.SESSION_COOKIE_NAME)] if str(settings.CSRF_COOKIE_NAME) in cookie_parser: del cookie_parser[str(settings.CSRF_COOKIE_NAME)] request_data['cookies'].update(cookie_parser) elif self.http_headerRE.match(header_name) and not header_name in self.blacklisted_http_headers: fixed_name = header_name.replace("http_", "", 1).replace('_', '-') request_data['headers'][fixed_name] = header[1] # Build the Via header protocolVersion = self.protocolRE.match(request.META['SERVER_PROTOCOL']) if protocolVersion is not None: protocolVersion = protocolVersion.group(1) else: protocolVersion = '1.1' via_header = "%s %s (Wirecloud-python-Proxy/1.1)" % (protocolVersion, get_current_domain(request)) if 'via' in request_data['headers']: request_data['headers']['via'] += ', ' + via_header else: request_data['headers']['via'] = via_header # XFF headers if 'x-forwarded-for' in request_data['headers']: request_data['headers']['x-forwarded-for'] += ', ' + request.META['REMOTE_ADDR'] else: request_data['headers']['x-forwarded-for'] = request.META['REMOTE_ADDR'] request_data['headers']['x-forwarded-host'] = host if 'x-forwarded-server' in request_data['headers']: del request_data['headers']['x-forwarded-server'] # Pass proxy processors to the new request try: for processor in get_request_proxy_processors(): processor.process_request(request_data) except ValidationError as e: return e.get_response(request) # Cookies cookie_header_content = ', '.join([cookie_parser[key].OutputString() for key in request_data['cookies']]) if cookie_header_content != '': request_data['headers']['Cookie'] = cookie_header_content # Open the request try: res = requests.request(request_data['method'], request_data['url'], headers=request_data['headers'], data=request_data['data'], stream=True, verify=getattr(settings, 'WIRECLOUD_HTTPS_VERIFY', True)) except requests.exceptions.Timeout as e: return build_error_response(request, 504, _('Gateway Timeout'), details=six.text_type(e)) except requests.exceptions.SSLError as e: return build_error_response(request, 502, _('SSL Error'), details=six.text_type(e)) except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError, requests.exceptions.TooManyRedirects) as e: return build_error_response(request, 504, _('Connection Error'), details=six.text_type(e)) # Build a Django response response = StreamingHttpResponse(res.raw.stream(4096, decode_content=False), status=res.status_code) if 'reason_phrase' in response: # pragma: no cover # Currently only django 1.6+ supports custom reason phrases response.reason_phrase = res.reason_phrase # Add all the headers received from the response for header in res.headers: header_lower = header.lower() if header_lower == 'set-cookie': for cookie in res.cookies: response.set_cookie(cookie.name, value=cookie.value, expires=cookie.expires, path=cookie.path) elif header_lower == 'via': via_header = via_header + ', ' + res.headers[header] elif is_valid_response_header(header_lower): response[header] = res.headers[header] # Pass proxy processors to the response for processor in get_response_proxy_processors(): response = processor.process_response(request_data, response) response['Via'] = via_header return response
def do_request(self, request, url, method): url = iri_to_uri(url) request_data = { "method": method, "url": url, "data": None, "headers": {}, "cookies": Cookie.SimpleCookie(), "user": request.user, "original-request": request, } # Request creation proto, host, cgi, param, query = urlparse.urlparse(url)[:5] # Extract headers from META if 'HTTP_TRANSFER_ENCODING' in request.META: return build_error_response(request, 500, "Wirecloud doesn't support requests using Transfer-Encodings") for header in request.META.items(): header_name = header[0].lower() if header_name == 'content_type' and header[1]: request_data['headers']["content-type"] = header[1] elif header_name == 'content_length' and header[1]: # Only take into account request body if the request has a # Content-Length header (we don't support chunked requests) request_data['data'] = request # It's better not propagate the Content-Length header as # request processors may change final data length. In addition # to this, the requests modules ignores the Content-Length # header and tries to obtain data length directly from the # data parameter. Therefore, providing this value in the len # attribute seems to be the best option request_data['data'].len = int(header[1]) elif header_name == 'cookie' or header_name == 'http_cookie': cookie_parser = Cookie.SimpleCookie(str(header[1])) del cookie_parser[settings.SESSION_COOKIE_NAME] if settings.CSRF_COOKIE_NAME in cookie_parser: del cookie_parser[settings.CSRF_COOKIE_NAME] request_data['cookies'].update(cookie_parser) elif self.http_headerRE.match(header_name) and not header_name in self.blacklisted_http_headers: fixed_name = header_name.replace("http_", "", 1).replace('_', '-') request_data['headers'][fixed_name] = header[1] # Build the Via header protocolVersion = self.protocolRE.match(request.META['SERVER_PROTOCOL']) if protocolVersion is not None: protocolVersion = protocolVersion.group(1) else: protocolVersion = '1.1' via_header = "%s %s (Wirecloud-python-Proxy/1.1)" % (protocolVersion, get_current_domain(request)) if 'via' in request_data['headers']: request_data['headers']['via'] += ', ' + via_header else: request_data['headers']['via'] = via_header # XFF headers if 'x-forwarded-for' in request_data['headers']: request_data['headers']['x-forwarded-for'] += ', ' + request.META['REMOTE_ADDR'] else: request_data['headers']['x-forwarded-for'] = request.META['REMOTE_ADDR'] request_data['headers']['x-forwarded-host'] = host if 'x-forwarded-server' in request_data['headers']: del request_data['headers']['x-forwarded-server'] # Pass proxy processors to the new request try: for processor in get_request_proxy_processors(): processor.process_request(request_data) except ValidationError as e: return e.get_response() # Cookies cookie_header_content = ', '.join([cookie_parser[key].OutputString() for key in request_data['cookies']]) if cookie_header_content != '': request_data['headers']['Cookie'] = cookie_header_content # Open the request try: res = requests.request(request_data['method'], request_data['url'], headers=request_data['headers'], data=request_data['data'], stream=True) except requests.exceptions.HTTPError: return HttpResponse(status=504) except requests.exceptions.ConnectionError: return HttpResponse(status=502) # Build a Django response response = StreamingHttpResponse(res.raw.stream(4096, decode_content=False)) # Set status code to the response response.status_code = res.status_code # Add all the headers received from the response for header in res.headers: header_lower = header.lower() if header_lower == 'set-cookie': for cookie in res.cookies: response.set_cookie(cookie.name, value=cookie.value, expires=cookie.expires, path=cookie.path) elif header_lower == 'via': via_header = via_header + ', ' + res.headers[header] elif is_valid_response_header(header_lower): response[header] = res.headers[header] # Pass proxy processors to the response for processor in get_response_proxy_processors(): response = processor.process_response(request_data, response) response['Via'] = via_header return response
def process_widget_code(request, resource): mode = request.GET.get('mode', 'classic') theme = request.GET.get('theme', get_active_theme_name()) widget_info = json.loads(resource.json_description) # check if the xhtml code has been cached if widget_info['contents']['cacheable'] is True: cache_key = resource.widget.xhtml.get_cache_key(get_current_domain(request), mode, theme) cache_entry = cache.get(cache_key) if cache_entry is not None: response = HttpResponse(cache_entry['code'], content_type=cache_entry['content_type']) patch_cache_headers(response, cache_entry['timestamp'], cache_entry['timeout']) return response # process xhtml xhtml = resource.widget.xhtml content_type = widget_info['contents'].get('contenttype', 'text/html') charset = widget_info['contents'].get('charset', 'utf-8') code = xhtml.code if not xhtml.cacheable or code == '': try: code = download_local_file(os.path.join(showcase_utils.wgt_deployer.root_dir, url2pathname(xhtml.url))) except Exception as e: if isinstance(e, IOError) and e.errno == errno.ENOENT: return build_response(request, 404, {'error_msg': _("Widget code not found"), 'details': "%s" % e}, WIDGET_ERROR_FORMATTERS) else: return build_response(request, 500, {'error_msg': _("Error reading widget code"), 'details': "%s" % e}, WIDGET_ERROR_FORMATTERS) else: # Code contents comes as unicode from persistence, we need bytes code = code.encode(charset) if xhtml.cacheable and (xhtml.code == '' or xhtml.code_timestamp is None): try: xhtml.code = code.decode(charset) except UnicodeDecodeError: msg = _('Widget code was not encoded using the specified charset (%(charset)s as stated in the widget description file).') % {'charset': charset} return build_response(request, 502, {'error_msg': msg}, WIDGET_ERROR_FORMATTERS) xhtml.code_timestamp = time.time() * 1000 xhtml.save() try: code = fix_widget_code(code, content_type, request, charset, xhtml.use_platform_style, process_requirements(widget_info['requirements']), mode, theme) except UnicodeDecodeError: msg = _('Widget code was not encoded using the specified charset (%(charset)s as stated in the widget description file).') % {'charset': charset} return build_response(request, 502, {'error_msg': msg}, WIDGET_ERROR_FORMATTERS) except Exception as e: msg = _('Error processing widget code') return build_response(request, 502, {'error_msg': msg, 'details':"%s" % e}, WIDGET_ERROR_FORMATTERS) if xhtml.cacheable: cache_timeout = 31536000 # 1 year cache_entry = { 'code': code, 'content_type': '%s; charset=%s' % (content_type, charset), 'timestamp': xhtml.code_timestamp, 'timeout': cache_timeout, } cache.set(cache_key, cache_entry, cache_timeout) else: cache_timeout = 0 response = HttpResponse(code, content_type='%s; charset=%s' % (content_type, charset)) patch_cache_headers(response, xhtml.code_timestamp, cache_timeout) return response
def read(self, request, vendor, name, version): resource = get_object_or_404(CatalogueResource.objects.select_related('widget__xhtml'), vendor=vendor, short_name=name, version=version) # For now, all widgets are freely accessible/distributable #if not resource.is_available_for(request.user): # return build_error_response(request, 403, "Forbidden") if resource.resource_type() != 'widget': raise Http404() mode = request.GET.get('mode', 'classic') widget_info = json.loads(resource.json_description) # check if the xhtml code has been cached if widget_info['contents']['cacheable'] is True: cache_key = resource.widget.xhtml.get_cache_key(get_current_domain(request), mode) cache_entry = cache.get(cache_key) if cache_entry is not None: response = HttpResponse(cache_entry['code'], content_type=cache_entry['content_type']) patch_cache_headers(response, cache_entry['timestamp'], cache_entry['timeout']) return response # process xhtml xhtml = resource.widget.xhtml content_type = widget_info['contents'].get('contenttype', 'text/html') charset = widget_info['contents'].get('charset', 'utf-8') force_base = False base_url = xhtml.url if not base_url.startswith(('http://', 'https://')): # Newer versions of Django urlencode urls created using reverse # Fix double encoding base_url = urlunquote(base_url) base_url = get_absolute_reverse_url('wirecloud.showcase_media', args=(base_url.split('/', 3)), request=request) force_base = True code = xhtml.code if not xhtml.cacheable or code == '': try: if xhtml.url.startswith(('http://', 'https://')): code = download_http_content(urljoin(base_url, xhtml.url), user=request.user) else: code = download_local_file(os.path.join(showcase_utils.wgt_deployer.root_dir, url2pathname(xhtml.url))) except Exception as e: return build_response(request, 502, {'error_msg': _("(X)HTML code is not accessible"), 'details': "%s" % e}, WIDGET_ERROR_FORMATTERS) else: # Code contents comes as unicode from persistence, we need bytes code = code.encode(charset) if xhtml.cacheable and (xhtml.code == '' or xhtml.code_timestamp is None): try: xhtml.code = code.decode(charset) except UnicodeDecodeError: msg = _('Widget code was not encoded using the specified charset (%(charset)s as stated in the widget description file).') % {'charset': charset} return build_response(request, 502, {'error_msg': msg}, WIDGET_ERROR_FORMATTERS) xhtml.code_timestamp = time.time() * 1000 xhtml.save() elif not xhtml.cacheable and xhtml.code != '': xhtml.code = '' xhtml.code_timestamp = None xhtml.save() try: code = fix_widget_code(code, base_url, content_type, request, charset, xhtml.use_platform_style, process_requirements(widget_info['requirements']), force_base, mode) except UnicodeDecodeError: msg = _('Widget code was not encoded using the specified charset (%(charset)s as stated in the widget description file).') % {'charset': charset} return build_response(request, 502, {'error_msg': msg}, WIDGET_ERROR_FORMATTERS) except Exception as e: msg = _('Error processing widget code') return build_response(request, 502, {'error_msg': msg, 'details':"%s" % e}, WIDGET_ERROR_FORMATTERS) if xhtml.cacheable: cache_timeout = 31536000 # 1 year cache_entry = { 'code': code, 'content_type': '%s; charset=%s' % (content_type, charset), 'timestamp': xhtml.code_timestamp, 'timeout': cache_timeout, } cache.set(cache_key, cache_entry, cache_timeout) else: cache_timeout = 0 response = HttpResponse(code, content_type='%s; charset=%s' % (content_type, charset)) patch_cache_headers(response, xhtml.code_timestamp, cache_timeout) return response
def process_widget_code(request, resource): mode = request.GET.get('mode', 'classic') theme = request.GET.get('theme', get_active_theme_name()) widget_info = json.loads(resource.json_description) # check if the xhtml code has been cached if widget_info['contents']['cacheable'] is True: cache_key = resource.widget.xhtml.get_cache_key( get_current_domain(request), mode, theme) cache_entry = cache.get(cache_key) if cache_entry is not None: response = HttpResponse(cache_entry['code'], content_type=cache_entry['content_type']) patch_cache_headers(response, cache_entry['timestamp'], cache_entry['timeout']) return response # process xhtml xhtml = resource.widget.xhtml content_type = widget_info['contents'].get('contenttype', 'text/html') charset = widget_info['contents'].get('charset', 'utf-8') code = xhtml.code if not xhtml.cacheable or code == '': try: code = download_local_file( os.path.join(showcase_utils.wgt_deployer.root_dir, url2pathname(xhtml.url))) except Exception as e: if isinstance(e, IOError) and e.errno == errno.ENOENT: return build_response(request, 404, { 'error_msg': _("Widget code not found"), 'details': "%s" % e }, WIDGET_ERROR_FORMATTERS) else: return build_response( request, 500, { 'error_msg': _("Error reading widget code"), 'details': "%s" % e }, WIDGET_ERROR_FORMATTERS) else: # Code contents comes as unicode from persistence, we need bytes code = code.encode(charset) if xhtml.cacheable and (xhtml.code == '' or xhtml.code_timestamp is None): try: xhtml.code = code.decode(charset) except UnicodeDecodeError: msg = _( 'Widget code was not encoded using the specified charset (%(charset)s as stated in the widget description file).' ) % { 'charset': charset } return build_response(request, 502, {'error_msg': msg}, WIDGET_ERROR_FORMATTERS) xhtml.code_timestamp = time.time() * 1000 xhtml.save() try: code = fix_widget_code( code, content_type, request, charset, xhtml.use_platform_style, process_requirements(widget_info['requirements']), mode, theme) except UnicodeDecodeError: msg = _( 'Widget code was not encoded using the specified charset (%(charset)s as stated in the widget description file).' ) % { 'charset': charset } return build_response(request, 502, {'error_msg': msg}, WIDGET_ERROR_FORMATTERS) except Exception as e: msg = _('Error processing widget code') return build_response(request, 502, { 'error_msg': msg, 'details': "%s" % e }, WIDGET_ERROR_FORMATTERS) if xhtml.cacheable: cache_timeout = 31536000 # 1 year cache_entry = { 'code': code, 'content_type': '%s; charset=%s' % (content_type, charset), 'timestamp': xhtml.code_timestamp, 'timeout': cache_timeout, } cache.set(cache_key, cache_entry, cache_timeout) else: cache_timeout = 0 response = HttpResponse(code, content_type='%s; charset=%s' % (content_type, charset)) patch_cache_headers(response, xhtml.code_timestamp, cache_timeout) return response
def read(self, request, vendor, name, version): resource = get_object_or_404(CatalogueResource.objects.select_related('widget__xhtml'), vendor=vendor, short_name=name, version=version) # For now, all widgets are freely accessible/distributable #if not resource.is_available_for(request.user): # return build_error_response(request, 403, "Forbidden") if resource.resource_type() != 'widget': raise Http404() mode = request.GET.get('mode', 'classic') widget_info = json.loads(resource.json_description) # check if the xhtml code has been cached if widget_info['contents']['cacheable'] is True: cache_key = resource.widget.xhtml.get_cache_key(get_current_domain(request), mode) cache_entry = cache.get(cache_key) if cache_entry is not None: response = HttpResponse(cache_entry['code'], content_type=cache_entry['content_type']) patch_cache_headers(response, cache_entry['timestamp'], cache_entry['timeout']) return response # process xhtml xhtml = resource.widget.xhtml content_type = widget_info['contents'].get('contenttype', 'text/html') charset = widget_info['contents'].get('charset', 'utf-8') force_base = False base_url = xhtml.url if not base_url.startswith(('http://', 'https://')): # Newer versions of Django urlencode urls created using reverse # Fix double encoding base_url = urlunquote(base_url) base_url = get_absolute_reverse_url('wirecloud.showcase_media', args=(base_url.split('/', 4)), request=request) force_base = True code = xhtml.code if not xhtml.cacheable or code == '': try: if xhtml.url.startswith(('http://', 'https://')): code = download_http_content(urljoin(base_url, xhtml.url), user=request.user) else: code = download_local_file(os.path.join(showcase_utils.wgt_deployer.root_dir, url2pathname(xhtml.url))) except Exception as e: return build_response(request, 502, {'error_msg': _("(X)HTML code is not accessible"), 'details': "%s" % e}, WIDGET_ERROR_FORMATTERS) else: # Code contents comes as unicode from persistence, we need bytes code = code.encode(charset) if xhtml.cacheable and (xhtml.code == '' or xhtml.code_timestamp is None): try: xhtml.code = code.decode(charset) except UnicodeDecodeError: msg = _('Widget code was not encoded using the specified charset (%(charset)s as stated in the widget description file).') % {'charset': charset} return build_response(request, 502, {'error_msg': msg}, WIDGET_ERROR_FORMATTERS) xhtml.code_timestamp = time.time() * 1000 xhtml.save() elif not xhtml.cacheable and xhtml.code != '': xhtml.code = '' xhtml.code_timestamp = None xhtml.save() try: code = fix_widget_code(code, base_url, content_type, request, charset, xhtml.use_platform_style, process_requirements(widget_info['requirements']), force_base, mode) except UnicodeDecodeError: msg = _('Widget code was not encoded using the specified charset (%(charset)s as stated in the widget description file).') % {'charset': charset} return build_response(request, 502, {'error_msg': msg}, WIDGET_ERROR_FORMATTERS) except Exception as e: msg = _('Error processing widget code') return build_response(request, 502, {'error_msg': msg, 'details':"%s" % e}, WIDGET_ERROR_FORMATTERS) if xhtml.cacheable: cache_timeout = 31536000 # 1 year cache_entry = { 'code': code, 'content_type': '%s; charset=%s' % (content_type, charset), 'timestamp': xhtml.code_timestamp, 'timeout': cache_timeout, } cache.set(cache_key, cache_entry, cache_timeout) else: cache_timeout = 0 response = HttpResponse(code, content_type='%s; charset=%s' % (content_type, charset)) patch_cache_headers(response, xhtml.code_timestamp, cache_timeout) return response
def do_request(self, request, url, method, request_data): url = iri_to_uri(url) request_data.update({ "method": method, "url": url, "original-request": request, }) request_data.setdefault("data", None) request_data.setdefault("headers", {}) request_data.setdefault("cookies", SimpleCookie()) request_data.setdefault("user", request.user) # Request creation proto, host, cgi, param, query = urlparse(url)[:5] # Build the Via header protocolVersion = self.protocolRE.match( request.META['SERVER_PROTOCOL']) if protocolVersion is not None: protocolVersion = protocolVersion.group(1) else: protocolVersion = '1.1' via_header = "%s %s (Wirecloud-python-Proxy/1.1)" % ( protocolVersion, get_current_domain(request)) if 'via' in request_data['headers']: request_data['headers']['via'] += ', ' + via_header else: request_data['headers']['via'] = via_header # XFF headers if 'x-forwarded-for' in request_data['headers']: request_data['headers'][ 'x-forwarded-for'] += ', ' + request.META['REMOTE_ADDR'] else: request_data['headers']['x-forwarded-for'] = request.META[ 'REMOTE_ADDR'] # Pass proxy processors to the new request try: for processor in get_request_proxy_processors(): processor.process_request(request_data) except ValidationError as e: return e.get_response(request) # Cookies cookie_header_content = ', '.join([ request_data['cookies'][key].OutputString() for key in request_data['cookies'] ]) if cookie_header_content != '': request_data['headers']['Cookie'] = cookie_header_content # Seems that Django or WSGI provides default values for the # Content-Length and Content-Type headers, so we are not able to detect # if the request provided them :( if str(request_data['headers'].get('content-length', '0')).strip() == '0': request_data['data'] = None if 'content-type' in request_data['headers']: del request_data['headers']['content-type'] # Open the request try: res = requests.request(request_data['method'], request_data['url'], headers=request_data['headers'], data=request_data['data'], stream=True, verify=getattr(settings, 'WIRECLOUD_HTTPS_VERIFY', True)) except requests.exceptions.Timeout as e: return build_error_response(request, 504, _('Gateway Timeout'), details=str(e)) except requests.exceptions.SSLError as e: return build_error_response(request, 502, _('SSL Error'), details=str(e)) except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError, requests.exceptions.TooManyRedirects) as e: return build_error_response(request, 504, _('Connection Error'), details=str(e)) # Build a Django response response = StreamingHttpResponse(res.raw.stream(4096, decode_content=False), status=res.status_code, reason=res.reason) # Add all the headers received from the response for header in res.headers: header_lower = header.lower() if header_lower == 'set-cookie': for cookie in res.cookies: response.set_cookie(cookie.name, value=cookie.value, expires=cookie.expires, path=cookie.path) elif header_lower == 'via': via_header = via_header + ', ' + res.headers[header] elif is_valid_response_header(header_lower): response[header] = res.headers[header] # Pass proxy processors to the response for processor in get_response_proxy_processors(): response = processor.process_response(request_data, response) response['Via'] = via_header return response