def set_url_query_parameter(url, param_name, param_value): """Set or replace a query parameter, and return the modified URL. Args: url: str. URL string which contains the query parameter. param_name: str. Parameter name to be removed. param_value: str. Set the parameter value, if it exists. Returns: str. Formated URL that has query parameter set or replaced. Raises: Exception. If the query parameter sent is not of string type, them this exception is raised. """ if not isinstance(param_name, python_utils.BASESTRING): raise Exception( 'URL query parameter name must be a string, received %s' % param_name) scheme, netloc, path, query_string, fragment = python_utils.url_split(url) query_params = python_utils.parse_query_string(query_string) query_params[param_name] = [param_value] new_query_string = python_utils.url_encode(query_params, doseq=True) return python_utils.url_unsplit( (scheme, netloc, path, new_query_string, fragment))
def sanitize_url(obj): """Takes a string representing a URL and sanitizes it. Args: obj: a string representing a URL. Returns: An empty string if the URL does not start with http:// or https:// except when the string is empty. Otherwise, returns the original URL. Raises: AssertionError: The string is non-empty and does not start with http:// or https:// """ if obj == '': return obj url_components = python_utils.url_split(obj) quoted_url_components = (python_utils.url_quote(component) for component in url_components) raw = python_utils.url_unsplit(quoted_url_components) acceptable = html_cleaner.filter_a('a', 'href', obj) assert acceptable, ('Invalid URL: Sanitized URL should start with ' '\'http://\' or \'https://\'; received %s' % raw) return raw
def filter_a(tag, name, value): """Returns whether the described attribute of a tag should be whitelisted. Args: tag: str. The name of the tag passed. name: str. The name of the attribute. value: str. The value of the attribute. Returns: bool. Whether the given attribute should be whitelisted. """ if tag != 'a': raise Exception('The filter_a method should only be used for a tags.') if name in ('title', 'target'): return True if name == 'href': url_components = python_utils.url_split(value) if url_components[0] in ['http', 'https']: return True logging.error('Found invalid URL href: %s' % value) return False
def dispatch(self): """Overrides dispatch method in webapp2 superclass. Raises: Exception. The CSRF token is missing. UnauthorizedUserException. The CSRF token is invalid. """ request_split = python_utils.url_split(self.request.uri) # If the request is to the old demo server, redirect it permanently to # the new demo server. if request_split.netloc == 'oppiaserver.appspot.com': self.redirect('https://oppiatestserver.appspot.com', permanent=True) return if not self._is_requested_path_currently_accessible_to_user(): self.handle_exception(self.TemporaryMaintenanceException(), self.app.debug) return if self.user_is_scheduled_for_deletion: self.redirect('/logout?redirect_url=%s' % feconf.PENDING_ACCOUNT_DELETION_URL) return if self.partially_logged_in and request_split.path != '/logout': self.redirect('/logout?redirect_url=%s' % self.request.uri) return if self.payload is not None and self.REQUIRE_PAYLOAD_CSRF_CHECK: try: # If user opens a new tab during signup process, the user_id # parameter is set to None and this causes the signup session # to expire. The code here checks if user is on the signup # page and the user_id is None, if that is the case an exception # is raised which is handled by the frontend by showing a # continue to registration modal. if 'signup' in self.request.uri and not self.user_id: raise self.UnauthorizedUserException( 'Registration session expired.') csrf_token = self.request.get('csrf_token') if not csrf_token: raise self.UnauthorizedUserException( 'Missing CSRF token. Changes were not saved. ' 'Please report this bug.') is_csrf_token_valid = CsrfTokenManager.is_csrf_token_valid( self.user_id, csrf_token) if not is_csrf_token_valid: raise self.UnauthorizedUserException( 'Your session has expired, and unfortunately your ' 'changes cannot be saved. Please refresh the page.') except Exception as e: logging.exception('%s: payload %s', e, self.payload) self.handle_exception(e, self.app.debug) return schema_validation_succeeded = True try: self.validate_and_normalize_args() except self.InvalidInputException as e: self.handle_exception(e, self.app.debug) schema_validation_succeeded = False # TODO(#13155): Remove this clause once all the handlers have had # schema validation implemented. except NotImplementedError as e: self.handle_exception(e, self.app.debug) schema_validation_succeeded = False if not schema_validation_succeeded: return super(BaseHandler, self).dispatch()
def render_template(self, filepath, iframe_restriction='DENY'): """Prepares an HTML response to be sent to the client. Args: filepath: str. The template filepath. iframe_restriction: str or None. Possible values are 'DENY' and 'SAMEORIGIN': DENY: Strictly prevents the template to load in an iframe. SAMEORIGIN: The template can only be displayed in a frame on the same origin as the page itself. """ values = self.values scheme, netloc, path, _, _ = python_utils.url_split(self.request.uri) values.update({ 'DEV_MODE': constants.DEV_MODE, 'DOMAIN_URL': '%s://%s' % (scheme, netloc), 'ACTIVITY_STATUS_PRIVATE': (rights_manager.ACTIVITY_STATUS_PRIVATE), 'ACTIVITY_STATUS_PUBLIC': (rights_manager.ACTIVITY_STATUS_PUBLIC), # The 'path' variable starts with a forward slash. 'FULL_URL': '%s://%s%s' % (scheme, netloc, path), }) if 'status_code' not in values: values['status_code'] = 200 if 'meta_name' not in values: values['meta_name'] = 'Personalized Online Learning from Oppia' if 'meta_description' not in values: values['meta_description'] = ( 'Oppia is a free, open-source learning platform. Join the ' 'community to create or try an exploration today!') # Create a new csrf token for inclusion in HTML responses. This assumes # that tokens generated in one handler will be sent back to a handler # with the same page name. self.response.cache_control.no_cache = True self.response.cache_control.must_revalidate = True self.response.headers[b'Strict-Transport-Security'] = ( b'max-age=31536000; includeSubDomains') self.response.headers[b'X-Content-Type-Options'] = b'nosniff' self.response.headers[b'X-Xss-Protection'] = b'1; mode=block' if iframe_restriction is not None: if iframe_restriction in ['SAMEORIGIN', 'DENY']: self.response.headers[ b'X-Frame-Options'] = python_utils.convert_to_bytes( iframe_restriction) else: raise Exception('Invalid X-Frame-Options: %s' % iframe_restriction) self.response.expires = 'Mon, 01 Jan 1990 00:00:00 GMT' self.response.pragma = 'no-cache' self.response.write( self.jinja2_env.get_template(filepath).render(**values))
def test_url_unsplit(self): response = python_utils.url_split('http://www.google.com') self.assertEqual(python_utils.url_unsplit(response), 'http://www.google.com')