def generate_formdata(req, resp, params): """sets prarams['form'] to pass to every endpoint. """ #print "here" form = dict() files = dict() if req.method == 'GET': di = parse_query_string(req.query_string) form = dict(di) params['form'], params['files'] = dict(form), dict(files) else: if 'json' in req.get_header('content-type', None): form = json.load(req.stream) params['form'], params['files'] = dict(form), dict(files) else: mimetype, options = parse_options_header(req.get_header('content-type')) data = req.stream.read() environ = {'wsgi.input': StringIO(data), 'CONTENT_LENGTH': str(len(data)), 'CONTENT_TYPE': req.get_header('content-type'), 'REQUEST_METHOD': 'POST'} stream, tempform, tempfiles = parse_form_data(environ) for item in tempform: form[item] = tempform[item] di = parse_query_string(req.query_string) for item in di: form[item] = di[item] for item in tempfiles: files[item] = tempfiles[item] params['form'], params['files'] = dict(form), dict(files) return True
def test_parse_query_string(self): query_strinq = ( 'a=http%3A%2F%2Ffalconframework.org%3Ftest%3D1' '&b=%7B%22test1%22%3A%20%22data1%22%' '2C%20%22test2%22%3A%20%22data2%22%7D' '&c=1,2,3' '&d=test' '&e=a,,%26%3D%2C' '&f=a&f=a%3Db' '&%C3%A9=a%3Db' ) decoded_url = 'http://falconframework.org?test=1' decoded_json = '{"test1": "data1", "test2": "data2"}' result = uri.parse_query_string(query_strinq) assert result['a'] == decoded_url assert result['b'] == decoded_json assert result['c'] == ['1', '2', '3'] assert result['d'] == 'test' assert result['e'] == ['a', '&=,'] assert result['f'] == ['a', 'a=b'] assert result['é'] == 'a=b' result = uri.parse_query_string(query_strinq, True) assert result['a'] == decoded_url assert result['b'] == decoded_json assert result['c'] == ['1', '2', '3'] assert result['d'] == 'test' assert result['e'] == ['a', '', '&=,'] assert result['f'] == ['a', 'a=b'] assert result['é'] == 'a=b'
def test_parse_query_string(self): query_strinq = ("a=http%3A%2F%2Ffalconframework.org%3Ftest%3D1" "&b=%7B%22test1%22%3A%20%22data1%22%" "2C%20%22test2%22%3A%20%22data2%22%7D" "&c=1,2,3" "&d=test" "&e=a,,%26%3D%2C" "&f=a&f=a%3Db" "&%C3%A9=a%3Db") decoded_url = 'http://falconframework.org?test=1' decoded_json = '{"test1": "data1", "test2": "data2"}' result = uri.parse_query_string(query_strinq) self.assertEqual(result['a'], decoded_url) self.assertEqual(result['b'], decoded_json) self.assertEqual(result['c'], ['1', '2', '3']) self.assertEqual(result['d'], 'test') self.assertEqual(result['e'], ['a', '&=,']) self.assertEqual(result['f'], ['a', 'a=b']) self.assertEqual(result[u'é'], 'a=b') result = uri.parse_query_string(query_strinq, True) self.assertEqual(result['a'], decoded_url) self.assertEqual(result['b'], decoded_json) self.assertEqual(result['c'], ['1', '2', '3']) self.assertEqual(result['d'], 'test') self.assertEqual(result['e'], ['a', '', '&=,']) self.assertEqual(result['f'], ['a', 'a=b']) self.assertEqual(result[u'é'], 'a=b')
def test_parse_query_string(self): query_strinq = ( "a=http%3A%2F%2Ffalconframework.org%3Ftest%3D1" "&b=%7B%22test1%22%3A%20%22data1%22%" "2C%20%22test2%22%3A%20%22data2%22%7D" "&c=1,2,3" "&d=test" "&e=a,,%26%3D%2C" "&f=a&f=a%3Db" "&%C3%A9=a%3Db" ) decoded_url = 'http://falconframework.org?test=1' decoded_json = '{"test1": "data1", "test2": "data2"}' result = uri.parse_query_string(query_strinq) self.assertEqual(result['a'], decoded_url) self.assertEqual(result['b'], decoded_json) self.assertEqual(result['c'], ['1', '2', '3']) self.assertEqual(result['d'], 'test') self.assertEqual(result['e'], ['a', '&=,']) self.assertEqual(result['f'], ['a', 'a=b']) self.assertEqual(result[u'é'], 'a=b') result = uri.parse_query_string(query_strinq, True) self.assertEqual(result['a'], decoded_url) self.assertEqual(result['b'], decoded_json) self.assertEqual(result['c'], ['1', '2', '3']) self.assertEqual(result['d'], 'test') self.assertEqual(result['e'], ['a', '', '&=,']) self.assertEqual(result['f'], ['a', 'a=b']) self.assertEqual(result[u'é'], 'a=b')
def test_parse_query_string(self): query_string = ('a=http%3A%2F%2Ffalconframework.org%3Ftest%3D1' '&b=%7B%22test1%22%3A%20%22data1%22%' '2C%20%22test2%22%3A%20%22data2%22%7D' '&c=1,2,3' '&d=test' '&e=a,,%26%3D%2C' '&f=a&f=a%3Db' '&%C3%A9=a%3Db') decoded_url = 'http://falconframework.org?test=1' decoded_json = '{"test1": "data1", "test2": "data2"}' result = uri.parse_query_string(query_string) assert result['a'] == decoded_url assert result['b'] == decoded_json assert result['c'] == ['1', '2', '3'] assert result['d'] == 'test' assert result['e'] == ['a', '&=,'] assert result['f'] == ['a', 'a=b'] assert result['é'] == 'a=b' result = uri.parse_query_string(query_string, True) assert result['a'] == decoded_url assert result['b'] == decoded_json assert result['c'] == ['1', '2', '3'] assert result['d'] == 'test' assert result['e'] == ['a', '', '&=,'] assert result['f'] == ['a', 'a=b'] assert result['é'] == 'a=b'
def generate_formdata(req, resp, params): form = dict() files = dict() if req.method == 'GET': di = parse_query_string(req.query_string) form = dict(di) params['form'], params['files'] = dict(form), dict(files) else: if 'json' in req.get_header('content-type', None): #if the method type is post "form" variable below can contain #only either the post body or the quer parameter at once, modify #umcomment the below commented line to store query parameters in "form" form = json.load(req.stream) #form = dict(parse_query_string(req.query_string)) params['form'], params['files'] = dict(form), dict(files) else: mimetype, options = parse_options_header(req.get_header('content-type')) data = req.stream.read() environ = {'wsgi.input':StringIO(data), 'CONTENT_LENGTH': str(len(data)), 'CONTENT_TYPE': req.get_header('content-type'), 'REQUEST_METHOD': 'POST'} stream, tempform, tempfiles = parse_form_data(environ) for item in tempform: form[item] = tempform[item] di = parse_query_string(req.query_string) for item in di: form[item] = di[item] for item in tempfiles: files[item] = tempfiles[item] params['form'], params['files'] = dict(form), dict(files) #print form #print params return True
def on_post(self, request, response): body = request.stream.read() encoded_raw_post_data = self.parse_request_data(body) pretty = request.get_param("pretty") if not pretty: pretty = parse_query_string(encoded_raw_post_data).get("pretty", False) data = request.get_param("data") if not data: data = parse_query_string(encoded_raw_post_data).get("data", False) if not data: data = encoded_raw_post_data if not data: return {"error": "No data posted or data incorrectly encoded"} action_str = request.get_param("action") if not action_str: action_str = parse_query_string(encoded_raw_post_data).get("action", None) if not action_str or action_str not in ACTIONS: action_str = "pos_tagging" action = ACTIONS[action_str]() tagged_json = action.parse(data) json_kwargs = {"separators": (',', ':')} if pretty: json_kwargs = {"indent": 4, "separators": (', ', ': ')} response.body = json.dumps(tagged_json, **json_kwargs)
def test_parse_query_string(self): query_strinq = ( "a=http%3A%2F%2Ffalconframework.org%3Ftest%3D1" "&b=%7B%22test1%22%3A%20%22data1%22%" "2C%20%22test2%22%3A%20%22data2%22%7D" "&c=1,2,3" "&d=test" "&e=a,,%26%3D%2C" "&f=a&f=a%3Db" "&%C3%A9=a%3Db" ) decoded_url = "http://falconframework.org?test=1" decoded_json = '{"test1": "data1", "test2": "data2"}' result = uri.parse_query_string(query_strinq) self.assertEqual(result["a"], decoded_url) self.assertEqual(result["b"], decoded_json) self.assertEqual(result["c"], ["1", "2", "3"]) self.assertEqual(result["d"], "test") self.assertEqual(result["e"], ["a", "&=,"]) self.assertEqual(result["f"], ["a", "a=b"]) self.assertEqual(result[u"é"], "a=b") result = uri.parse_query_string(query_strinq, True) self.assertEqual(result["a"], decoded_url) self.assertEqual(result["b"], decoded_json) self.assertEqual(result["c"], ["1", "2", "3"]) self.assertEqual(result["d"], "test") self.assertEqual(result["e"], ["a", "", "&=,"]) self.assertEqual(result["f"], ["a", "a=b"]) self.assertEqual(result[u"é"], "a=b")
def _parse_form_urlencoded(self): content_length = self.content_length if not content_length: return body = self.stream.read(content_length) # NOTE(kgriffs): According to http://goo.gl/6rlcux the # body should be US-ASCII. Enforcing this also helps # catch malicious input. try: body = body.decode('ascii') except UnicodeDecodeError: body = None self.log_error('Non-ASCII characters found in form body ' 'with Content-Type of ' 'application/x-www-form-urlencoded. Body ' 'will be ignored.') if body: extra_params = parse_query_string( body, keep_blank_qs_values=self.options.keep_blank_qs_values, parse_qs_csv=self.options.auto_parse_qs_csv, ) self._params.update(extra_params)
def on_post(self, req, resp): form_body = uri.parse_query_string(req.context['body']) try: username = form_body['username'] password = form_body['password'] except KeyError: raise HTTPFound('/login') if not auth.valid_username(username): logger.warn('Tried to login with invalid username %s', username) if self.debug: flash_message(req, 'Invalid username', 'danger') else: flash_message(req, 'Invalid credentials', 'danger') raise HTTPFound('/login') if self.auth_manager.authenticate(username, password): logger.info('Successful login for %s', username) auth.login_user(req, username) else: logger.warn('Failed login for %s', username) flash_message(req, 'Invalid credentials', 'danger') raise HTTPFound('/login') # Remove newlines to prevent HTTP request splitting url = req.get_param('next', default='').replace('\n', '') if not url or url.startswith('/'): raise HTTPFound(url or default_route) else: raise HTTPBadRequest('Invalid next parameter', '')
def on_get(self, req, resp, id=None, offset=0, limit=200): """Get all subscribers if no query args. If email in query args then return subscriber matching email. If id in route return that object.""" args = parse_query_string(req.query_string) email = args.get('email', None) if args.get('limit'): try: limit = int(args.get('limit')) if limit > 200: raise ValueError('Limit can not exceed 200') except ValueError as e: raise HTTPBadRequest('Invalid value for limit', e.message) if args.get('offset'): try: offset = int(args.get('offset')) except ValueError as e: raise HTTPBadRequest('Invalid value for limit', e.message) try: rdb = RethinkDBClient() if id: resp.body = rdb.get(self._table_name, 'id', id) elif email: resp.body = rdb.get(self._table_name, 'email', email) elif limit: resp.body = rdb.get_all(self._table_name, offset * limit, limit) else: resp.status = HTTP_400 resp.body = bad_request(info='Invalid request') except RqlError as e: raise HTTPBadRequest('Invalid request', e.message)
def _parse_form_urlencoded(self): # NOTE(kgriffs): This assumes self.stream has been patched # above in the case of wsgiref, so that self.content_length # is not needed. Normally we just avoid accessing # self.content_length, because it is a little expensive # to call. We could cache self.content_length, but the # overhead to do that won't usually be helpful, since # content length will only ever be read once per # request in most cases. body = self.stream.read() # NOTE(kgriffs): According to http://goo.gl/6rlcux the # body should be US-ASCII. Enforcing this also helps # catch malicious input. try: body = body.decode('ascii') except UnicodeDecodeError: body = None self.log_error('Non-ASCII characters found in form body ' 'with Content-Type of ' 'application/x-www-form-urlencoded. Body ' 'will be ignored.') if body: extra_params = parse_query_string( body, keep_blank_qs_values=self.options.keep_blank_qs_values, parse_qs_csv=self.options.auto_parse_qs_csv, ) self._params.update(extra_params)
def _parse_form_urlencoded(self): content_length = self.content_length if not content_length: return body = self.stream.read(content_length) # NOTE(kgriffs): According to http://goo.gl/6rlcux the # body should be US-ASCII. Enforcing this also helps # catch malicious input. try: body = body.decode('ascii') except UnicodeDecodeError: body = None self.log_error('Non-ASCII characters found in form body ' 'with Content-Type of ' 'application/x-www-form-urlencoded. Body ' 'will be ignored.') if body: extra_params = parse_query_string( body, keep_blank_qs_values=self.options.keep_blank_qs_values, parse_qs_csv=self.options.auto_parse_qs_csv, ) self._params.update(extra_params)
def _parse_form_urlencoded(self): # NOTE(kgriffs): This assumes self.stream has been patched # above in the case of wsgiref, so that self.content_length # is not needed. Normally we just avoid accessing # self.content_length, because it is a little expensive # to call. We could cache self.content_length, but the # overhead to do that won't usually be helpful, since # content length will only ever be read once per # request in most cases. body = self.stream.read() # NOTE(kgriffs): According to http://goo.gl/6rlcux the # body should be US-ASCII. Enforcing this also helps # catch malicious input. try: body = body.decode("ascii") except UnicodeDecodeError: body = None self.log_error( "Non-ASCII characters found in form body " "with Content-Type of " "application/x-www-form-urlencoded. Body " "will be ignored." ) if body: extra_params = parse_query_string(body, keep_blank_qs_values=self.options.keep_blank_qs_values) self._params.update(extra_params)
def process_resource(self, req, resp, resource, params): """ :param req: Falcon request :type req: falcon.request.Request :param resp: Falcon response :type resp: falcon.response.Response :param resource: :type resource: falcon_dbapi.resources.base.BaseCollectionResource| falcon_dbapi.resources.base.BaseSingleResource :param params: parameters dict :type params: dict """ if resource is None or req.method not in ['POST', 'PUT', 'PATCH']: return body = req.stream.read() if not body: raise falcon.HTTPBadRequest('Empty request body', 'At least one value is required') try: body = body.decode('utf-8') except UnicodeDecodeError: raise falcon.HTTPBadRequest('Invalid request body', 'A valid UTF-8 encoded document is required') req.context['doc'] = parse_query_string(body, keep_blank_qs_values=True, parse_qs_csv=False)
def on_post(req, resp): login_info = uri.parse_query_string(req.context['body']) user = login_info.get('username') password = login_info.get('password') if user is None or password is None: raise HTTPBadRequest('Invalid login attempt', 'Missing user/password') if not auth_manager.authenticate(user, password): raise HTTPUnauthorized('Authentication failure', 'bad login credentials', '') connection = db.connect() cursor = connection.cursor(db.DictCursor) data = get_user_data(None, {'name': user}, dbinfo=(connection, cursor)) if not data: cursor.close() connection.close() raise HTTPNotFound() session = req.env['beaker.session'] session['user'] = user session.save() csrf_token = '%x' % SystemRandom().getrandbits(128) cursor.execute( 'INSERT INTO `session` (`id`, `csrf_token`) VALUES (%s, %s)', (req.env['beaker.session']['_id'], csrf_token)) connection.commit() cursor.close() connection.close() # TODO: purge out of date csrf token data[0]['csrf_token'] = csrf_token resp.body = dumps(data[0])
def on_get(self, req, resp): args = parse_query_string(req.query_string) image_urls = {} try: # request access token code = args.get('code') url = '{0}?{1}={2}&{3}={4}&{5}={6}&{7}={8}&{9}={10}'.format( CONFIG['access_token_url'], 'client_id', CONFIG['access_key'], 'client_secret', CONFIG['secret_key'], 'redirect_uri', 'http://localhost:8000/callback', 'code', code, 'grant_type', 'authorization_code') q = requests.post(url) # Save access token access_token = q.json().get('access_token', None) CACHE.set('access_token', access_token) # TODO: Use proper query string url = '{0}?{1}={2}&{3}={4}'.format(CONFIG['random_photo_url'], 'query', list(get_conditions())[0], 'orientation', 'landscape') q = requests.get( url, headers={'Authorization': 'Bearer {0}'.format(access_token)}) print(q.status_code) print(q.content) print(q.json()['urls']) if q.status_code == 200: image_urls = q.json()['urls'] resp.status = falcon.HTTP_200 resp.body = json.dumps(image_urls) except Exception as exc: traceback.print_exc()
def _parse_form_urlencoded(self): # PERF(kgriffs): Technically, we should spend a few more # cycles and parse the content type for real, but # this heuristic will work virtually all the time. if (self.content_type and 'application/x-www-form-urlencoded' in self.content_type): # NOTE(kgriffs): This assumes self.stream has been patched # above in the case of wsgiref, so that self.content_length # is not needed. Normally we just avoid accessing # self.content_length, because it is a little expensive # to call. We could cache self.content_length, but the # overhead to do that won't usually be helpful, since # content length will only ever be read once per # request in most cases. body = self.stream.read() # NOTE(kgriffs): According to http://goo.gl/6rlcux the # body should be US-ASCII. Enforcing this also helps # catch malicious input. try: body = body.decode('ascii') except UnicodeDecodeError: body = None self.log_error('Non-ASCII characters found in form body ' 'with Content-Type of ' 'application/x-www-form-urlencoded. Body ' 'will be ignored.') if body: extra_params = uri.parse_query_string(uri.decode(body)) self._params.update(extra_params)
def on_post(self, req, resp): form_body = uri.parse_query_string(req.context['body']) try: template_subject = form_body['templateSubject'] template_body = form_body['templateBody'] application = form_body['application'] except KeyError: raise HTTPBadRequest('Missing keys from post body', '') if not application: resp.body = ujson.dumps({'error': 'No application found'}) resp.status = falcon.HTTP_400 return app_json = get_local(req, 'applications/%s' % application) sample_context_str = app_json.get('sample_context') if not sample_context_str: resp.body = ujson.dumps({'error': 'Missing sample_context from application config'}) resp.status = falcon.HTTP_400 logger.error('Missing sample context for app %s', application) return try: sample_context = ujson.loads(sample_context_str) except Exception: resp.body = ujson.dumps({'error': 'Invalid application sample_context'}) resp.status = falcon.HTTP_400 logger.exception('Bad sample context for app %s', application) return # TODO: also move iris meta var to api iris_sample_context = { "message_id": 5456900, "target": "user", "priority": "Urgent", "application": "Autoalerts", "plan": "default plan", "plan_id": 1843, "incident_id": 178293332, "template": "default template" } sample_context['iris'] = iris_sample_context environment = SandboxedEnvironment() try: subject_template = environment.from_string(template_subject) body_template = environment.from_string(template_body) except Exception as e: resp.body = ujson.dumps({'error': str(e), 'lineno': e.lineno}) resp.status = falcon.HTTP_400 else: resp.body = ujson.dumps({ 'template_subject': subject_template.render(sample_context), 'template_body': body_template.render(sample_context) })
def get_query_endtime_timestamp(req): try: params = parse_query_string(req.query_string) if 'end_time' in params: return _convert_time_string(params['end_time']) else: return None except Exception as ex: LOG.debug(ex) raise falcon.HTTPBadRequest('Bad request', ex.message)
def get_query_period(req): try: params = parse_query_string(req.query_string) if 'period' in params: return params['period'] else: return None except Exception as ex: LOG.debug(ex) raise falcon.HTTPBadRequest('Bad request', ex.message)
def deserialize(self, stream, content_type, content_length): body = stream.read() # NOTE(kgriffs): According to http://goo.gl/6rlcux the # body should be US-ASCII. Enforcing this also helps # catch malicious input. body = body.decode('ascii') return parse_query_string(body, keep_blank=self.keep_blank, csv=self.csv)
def _deserialize(self, body): try: # NOTE(kgriffs): According to http://goo.gl/6rlcux the # body should be US-ASCII. Enforcing this also helps # catch malicious input. body = body.decode('ascii') return parse_query_string(body, keep_blank=self._keep_blank, csv=self._csv) except Exception as err: raise errors.MediaMalformedError('URL-encoded') from err
def generate_formdata(req, resp, params): """sets prarams['form'] to pass to every endpoint. """ #print "here" form = dict() files = dict() if req.method == 'GET': di = parse_query_string(req.query_string) form = dict(di) params['form'], params['files'] = dict(form), dict(files) return True
def generate_formdata(req, resp, params): """sets prarams['form'] to pass to every endpoint. """ print "here" form = dict() files = dict() if req.method == 'GET': di = parse_query_string(req.query_string) form = dict(di) params['form'], params['files'] = dict(form), dict(files) else: if 'json' in req.get_header('content-type', None): form = json.load(req.stream) params['form'], params['files'] = dict(form), dict(files) else: mimetype, options = parse_options_header( req.get_header('content-type')) print mimetype data = req.stream.read() #print data environ = { 'wsgi.input': StringIO(data), 'CONTENT_LENGTH': str(len(data)), 'CONTENT_TYPE': req.get_header('content-type'), 'REQUEST_METHOD': 'POST' } stream, tempform, tempfiles = parse_form_data(environ) print "tempform", tempform print "stream", stream print "tempfiles", tempfiles for item in tempform: form[item] = tempform[item] di = parse_query_string(req.query_string) for item in di: form[item] = di[item] for item in tempfiles: files[item] = tempfiles[item] params['form'], params['files'] = dict(form), dict(files) print "test" return True
def on_get(self, req, resp): """ GET handler of match service :param req: Get string like ?first_id=X&second_id=Y where first_id and second_id are vars filled with id-s to be checked. X and Y in this case are ints! :param resp: JSON + HTTP/resp code depends of algorithm branch, see the code :return: """ query = uri.parse_query_string(req.query_string) # if [x for x in query if x not in ['first_id', 'second_id']]: # raise try: query['first_id'] = int(query['first_id']) query['second_id'] = int(query['second_id']) except(KeyError, TypeError): logger.warn("'runtime:endpoint.ServiceEndpoint.on_get' parsing query parameters error") resp.status = falcon.HTTP_500 resp.body = ujson.dumps({ 'status': 'error', 'note': 'query error' }) return sets_dict = {x: set(redis_client.smembers(query[x])) for x in ['first_id', 'second_id']} empty_ids = [x[0] for x in sets_dict.items() if x[1] == set([])] if len(empty_ids) > 0: resp.status = falcon.HTTP_404 resp.body = ujson.dumps({ 'status': 'not_found', 'ids': empty_ids, 'note': "some id's are not found in db" }) else: intersect_set = reduce(lambda l, k: l & k, sets_dict.values()) if len(intersect_set) > 0: resp.status = falcon.HTTP_200 resp.body = ujson.dumps({ 'status': 'not_connected', 'id': [query['first_id'], query['second_id']] }) else: resp.status = falcon.HTTP_200 resp.body = ujson.dumps({ 'status': 'connected', 'id': [query['first_id'], query['second_id']] })
def get_x_tenant_or_tenant_id(req, delegate_authorized_roles): """Evaluates whether the tenant ID or cross tenant ID should be returned. :param req: HTTP request object. :param delegate_authorized_roles: List of authorized roles that have delegate privileges. :returns: Returns the cross tenant or tenant ID. """ if is_in_role(req, delegate_authorized_roles): params = parse_query_string(req.query_string) if 'tenant_id' in params: tenant_id = params['tenant_id'] return tenant_id return get_tenant_id(req)
def generate_formdata(req, resp, params): form = dict() files = dict() if req.method == 'GET': di = parse_query_string(req.query_string) form = dict(di) params['form'], params['files'] = dict(form), dict(files) else: if 'json' in req.get_header('content-type', None): #if the method type is post "form" variable below can contain #only either the post body or the quer parameter at once, modify #umcomment the below commented line to store query parameters in "form" form = json.load(req.stream) #form = dict(parse_query_string(req.query_string)) params['form'], params['files'] = dict(form), dict(files) else: mimetype, options = parse_options_header( req.get_header('content-type')) data = req.stream.read() environ = { 'wsgi.input': StringIO(data), 'CONTENT_LENGTH': str(len(data)), 'CONTENT_TYPE': req.get_header('content-type'), 'REQUEST_METHOD': 'POST' } stream, tempform, tempfiles = parse_form_data(environ) for item in tempform: form[item] = tempform[item] di = parse_query_string(req.query_string) for item in di: form[item] = di[item] for item in tempfiles: files[item] = tempfiles[item] params['form'], params['files'] = dict(form), dict(files) #print form #print params return True
def get_query_statistics(req): try: params = parse_query_string(req.query_string) if 'statistics' in params: statistics = params['statistics'].split(',') statistics = [statistic.lower() for statistic in statistics] if not all(statistic in ['avg', 'min', 'max', 'count', 'sum'] for statistic in statistics): raise Exception("Invalid statistic") return statistics else: raise Exception("Missing statistics") except Exception as ex: LOG.debug(ex) raise falcon.HTTPBadRequest('Bad request', ex.message)
def deserialize(self, stream, content_type, content_length): body = stream.read() # NOTE(kgriffs): According to http://goo.gl/6rlcux the # body should be US-ASCII. Enforcing this also helps # catch malicious input. body = body.decode('ascii') # TODO(vytas): We are not short-circuiting here for performance (as # empty URL-encoded payload should not be a common case), but to work # around #1600 if not body: return {} return parse_query_string(body, keep_blank=self.keep_blank, csv=self.csv)
def parse_form_body(req): if (req.content_type is not None and "application/x-www-form-urlencoded" in req.content_type): body = req.stream.read() try: body = body.decode("ascii") except UnicodeDecodeError: body = None req.log_error("Non-ASCII characters found in form body " "with Content-Type of " "application/x-www-form-urlencoded. Body " "will be ignored.") if body: return parse_query_string( body, keep_blank_qs_values=req.options.keep_blank_qs_values) return {}
def get_query_name(req, name_required=False): """ Returns the query param "name" if supplied. :param req: HTTP request object. """ try: params = parse_query_string(req.query_string) if 'name' in params: name = params['name'] return name else: if name_required: raise Exception("Missing name") else: return '' except Exception as ex: LOG.debug(ex) raise falcon.HTTPBadRequest('Bad request', ex.message)
def on_post(self, req, resp): form_body = uri.parse_query_string(req.context['body']) try: username = form_body['username'] password = form_body['password'] except KeyError: raise HTTPFound('/login') if self.auth_manager.authenticate(username, password): logger.info('Successful login for %s', username) auth.login_user(req, username) else: logger.warn('Failed login for %s', username) raise HTTPFound('/login') url = req.get_param('next') if not url or url.startswith('/'): raise HTTPFound(url or default_route) else: raise HTTPBadRequest('Invalid next parameter', '')
def get_query_dimensions(req): """Gets and parses the query param dimensions. :param req: HTTP request object. :return: Returns the dimensions as a JSON object :raises falcon.HTTPBadRequest: If dimensions are malformed. """ try: params = parse_query_string(req.query_string) dimensions = {} if 'dimensions' in params: dimensions_str = params['dimensions'] dimensions_str_array = dimensions_str.split(',') for dimension in dimensions_str_array: dimension_name_value = dimension.split(':') if len(dimension_name_value) == 2: dimensions[dimension_name_value[0]] = dimension_name_value[ 1] else: raise Exception('Dimensions are malformed') return dimensions except Exception as ex: LOG.debug(ex) raise falcon.HTTPBadRequest('Bad request', ex.message)
def test_to_query_str_encoding(self, params, csv): query_str = falcon.to_query_str(params, comma_delimited_lists=csv, prefix=False) assert uri.parse_query_string(query_str, csv=csv) == params
def __init__(self, env): """Initialize attributes based on a WSGI environment dict Note: Request is not meant to be instantiated directory by responders. Args: env: A WSGI environment dict passed in from the server. See also the PEP-3333 spec. """ self.env = env self._wsgierrors = env['wsgi.errors'] self.stream = env['wsgi.input'] self.method = env['REQUEST_METHOD'] # Normalize path path = env['PATH_INFO'] if path: if len(path) != 1 and path.endswith('/'): self.path = path[:-1] else: self.path = path else: self.path = '/' # QUERY_STRING isn't required to be in env, so let's check # PERF: if...in is faster than using env.get(...) if 'QUERY_STRING' in env and env['QUERY_STRING']: # TODO(kgriffs): Should this escape individual values instead # of the entire string? The way it is now, this: # # x=ab%2Bcd%3D42%2C9 # # becomes this: # # x=ab+cd=42,9 # self.query_string = uri.decode(env['QUERY_STRING']) else: self.query_string = six.text_type() # PERF: Don't parse it if we don't have to! if self.query_string: self._params = uri.parse_query_string(self.query_string) else: self._params = {} helpers.normalize_headers(env) self._cached_headers = {} self._cached_uri = None self._cached_relative_uri = None # NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust, # normalizing semantics between, e.g., gunicorn and wsgiref. if isinstance(self.stream, NativeStream): # pragma: nocover # NOTE(kgriffs): coverage can't detect that this *is* actually # covered since the test that does so uses multiprocessing. self.stream = helpers.Body(self.stream, self.content_length)
def __init__(self, env, options=None): global _maybe_wrap_wsgi_stream self.env = env self.options = options if options else RequestOptions() self._wsgierrors = env["wsgi.errors"] self.stream = env["wsgi.input"] self.method = env["REQUEST_METHOD"] # Normalize path path = env["PATH_INFO"] if path: if six.PY3: # PEP 3333 specifies that PATH_INFO variable are always # "bytes tunneled as latin-1" and must be encoded back path = path.encode("latin1").decode("utf-8", "replace") if len(path) != 1 and path.endswith("/"): self.path = path[:-1] else: self.path = path else: self.path = "/" # PERF(ueg1990): try/catch cheaper and faster (and more Pythonic) try: self.query_string = env["QUERY_STRING"] except KeyError: self.query_string = "" self._params = {} else: if self.query_string: self._params = parse_query_string( self.query_string, keep_blank_qs_values=self.options.keep_blank_qs_values ) else: self._params = {} self._cookies = None self._cached_headers = None self._cached_uri = None self._cached_relative_uri = None self._cached_access_route = None try: self.content_type = self.env["CONTENT_TYPE"] except KeyError: self.content_type = None # NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust, # normalizing semantics between, e.g., gunicorn and wsgiref. if _maybe_wrap_wsgi_stream: if isinstance(self.stream, (NativeStream, InputWrapper)): self._wrap_stream() else: # PERF(kgriffs): If self.stream does not need to be wrapped # this time, it never needs to be wrapped since the server # will continue using the same type for wsgi.input. _maybe_wrap_wsgi_stream = False # PERF(kgriffs): Technically, we should spend a few more # cycles and parse the content type for real, but # this heuristic will work virtually all the time. if ( self.options.auto_parse_form_urlencoded and self.content_type is not None and "application/x-www-form-urlencoded" in self.content_type ): self._parse_form_urlencoded() if self.context_type is None: # Literal syntax is more efficient than using dict() self.context = {} else: self.context = self.context_type()
def __init__(self, scope, receive, first_event=None, options=None): # ===================================================================== # Prepare headers # ===================================================================== req_headers = {} for header_name, header_value in scope['headers']: # NOTE(kgriffs): According to ASGI 3.0, header names are always # lowercased, and both name and value are byte strings. Although # technically header names and values are restricted to US-ASCII # we decode later (just-in-time) using the default 'utf-8' because # it is a little faster than passing an encoding option (except # under Cython). # # The reason we wait to decode is that the typical app will not # need to decode all request headers, and we usually can just # leave the header name as a byte string and look it up that way. # # NOTE(kgriffs): There are no standard request headers that # allow multiple instances to appear in the request while also # disallowing list syntax. if (header_name not in req_headers or header_name in _SINGLETON_HEADERS_BYTESTR): req_headers[header_name] = header_value else: req_headers[header_name] += b',' + header_value self._asgi_headers = req_headers # PERF(vytas): Fall back to class variable(s) when unset. # self._cached_headers = None # ===================================================================== # Misc. # ===================================================================== # PERF(vytas): Fall back to class variable(s) when unset. # self._asgi_server_cached = None # Lazy self.scope = scope self.is_websocket = scope['type'] == 'websocket' self.options = options if options else request.RequestOptions() # PERF(vytas): Fall back to class variable(s) when unset. # self._wsgierrors = None self.method = 'GET' if self.is_websocket else scope['method'] self.uri_template = None # PERF(vytas): Fall back to class variable(s) when unset. # self._media = _UNSET # self._media_error = None # TODO(kgriffs): ASGI does not specify whether 'path' may be empty, # as was allowed for WSGI. path = scope['path'] or '/' if (self.options.strip_url_path_trailing_slash and len(path) != 1 and path.endswith('/')): self.path = path[:-1] else: self.path = path query_string = scope['query_string'].decode() self.query_string = query_string if query_string: self._params = parse_query_string( query_string, keep_blank=self.options.keep_blank_qs_values, csv=self.options.auto_parse_qs_csv, ) else: self._params = {} # PERF(vytas): Fall back to class variable(s) when unset. # self._cached_access_route = None # self._cached_forwarded = None # self._cached_forwarded_prefix = None # self._cached_forwarded_uri = None # self._cached_prefix = None # self._cached_relative_uri = None # self._cached_uri = None if self.method == 'GET': # NOTE(vytas): We do not really expect the Content-Type to be # non-ASCII, however we assume ISO-8859-1 here for maximum # compatibility with WSGI. # PERF(kgriffs): Normally we expect no Content-Type header, so # use this pattern which is a little bit faster than dict.get() if b'content-type' in req_headers: self.content_type = req_headers[b'content-type'].decode( 'latin1') else: self.content_type = None else: # PERF(kgriffs): This is the most performant pattern when we expect # the key to be present most of the time. try: self.content_type = req_headers[b'content-type'].decode( 'latin1') except KeyError: self.content_type = None # ===================================================================== # The request body stream is created lazily # ===================================================================== # NOTE(kgriffs): The ASGI spec states that "you should not trigger # on a connection opening alone". I take this to mean that the app # should have the opportunity to respond with a 401, for example, # without having to first read any of the body. This is accomplished # in Falcon by only reading the first data event when the app attempts # to read from req.stream for the first time, and in uvicorn # (for example) by not confirming a 100 Continue request unless # the app calls receive() to read the request body. # PERF(vytas): Fall back to class variable(s) when unset. # self._stream = None self._receive = receive self._first_event = first_event # ===================================================================== # Create a context object # ===================================================================== self.context = self.context_type()
def __init__(self, env): self.env = env if self.context_type is None: # Literal syntax is more efficient than using dict() self.context = {} else: # pylint will detect this as not-callable because it only sees the # declaration of None, not whatever type a subclass may have set. self.context = self.context_type() # pylint: disable=not-callable self._wsgierrors = env['wsgi.errors'] self.stream = env['wsgi.input'] self.method = env['REQUEST_METHOD'] # Normalize path path = env['PATH_INFO'] if path: if len(path) != 1 and path.endswith('/'): self.path = path[:-1] else: self.path = path else: self.path = '/' # QUERY_STRING isn't required to be in env, so let's check # PERF: if...in is faster than using env.get(...) if 'QUERY_STRING' in env and env['QUERY_STRING']: # TODO(kgriffs): Should this escape individual values instead # of the entire string? The way it is now, this: # # x=ab%2Bcd%3D42%2C9 # # becomes this: # # x=ab+cd=42,9 # self.query_string = uri.decode(env['QUERY_STRING']) else: self.query_string = six.text_type() # PERF: Don't parse it if we don't have to! if self.query_string: self._params = uri.parse_query_string(self.query_string) else: self._params = {} helpers.normalize_headers(env) self._cached_headers = {} self._cached_uri = None self._cached_relative_uri = None self.content_type = self._get_header_by_wsgi_name('HTTP_CONTENT_TYPE') # NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust, # normalizing semantics between, e.g., gunicorn and wsgiref. if isinstance(self.stream, NativeStream): # pragma: nocover # NOTE(kgriffs): coverage can't detect that this *is* actually # covered since the test that does so uses multiprocessing. self.stream = helpers.Body(self.stream, self.content_length) self._parse_form_urlencoded()
def __init__(self, env, options=None): global _maybe_wrap_wsgi_stream self.env = env self.options = options if options else RequestOptions() self._wsgierrors = env['wsgi.errors'] self.stream = env['wsgi.input'] self.method = env['REQUEST_METHOD'] # Normalize path path = env['PATH_INFO'] if path: if six.PY3: # PEP 3333 specifies that PATH_INFO variable are always # "bytes tunneled as latin-1" and must be encoded back path = path.encode('latin1').decode('utf-8', 'replace') if len(path) != 1 and path.endswith('/'): self.path = path[:-1] else: self.path = path else: self.path = '/' # PERF(ueg1990): try/catch cheaper and faster (and more Pythonic) try: self.query_string = env['QUERY_STRING'] except KeyError: self.query_string = '' self._params = {} else: if self.query_string: self._params = parse_query_string( self.query_string, keep_blank_qs_values=self.options.keep_blank_qs_values, parse_qs_csv=self.options.auto_parse_qs_csv, ) else: self._params = {} self._cookies = None self._cached_headers = None self._cached_uri = None self._cached_relative_uri = None self._cached_access_route = None try: self.content_type = self.env['CONTENT_TYPE'] except KeyError: self.content_type = None # NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust, # normalizing semantics between, e.g., gunicorn and wsgiref. if _maybe_wrap_wsgi_stream: if isinstance(self.stream, ( NativeStream, InputWrapper, )): self._wrap_stream() else: # PERF(kgriffs): If self.stream does not need to be wrapped # this time, it never needs to be wrapped since the server # will continue using the same type for wsgi.input. _maybe_wrap_wsgi_stream = False # PERF(kgriffs): Technically, we should spend a few more # cycles and parse the content type for real, but # this heuristic will work virtually all the time. if (self.options.auto_parse_form_urlencoded and self.content_type is not None and 'application/x-www-form-urlencoded' in self.content_type): self._parse_form_urlencoded() if self.context_type is None: # Literal syntax is more efficient than using dict() self.context = {} else: self.context = self.context_type()
def __init__(self, env): self.env = env if self.context_type is None: # Literal syntax is more efficient than using dict() self.context = {} else: # pylint will detect this as not-callable because it only sees the # declaration of None, not whatever type a subclass may have set. self.context = self.context_type() # pylint: disable=not-callable self._wsgierrors = env['wsgi.errors'] self.stream = env['wsgi.input'] self.method = env['REQUEST_METHOD'] # Normalize path path = env['PATH_INFO'] if path: if len(path) != 1 and path.endswith('/'): self.path = path[:-1] else: self.path = path else: self.path = '/' # QUERY_STRING isn't required to be in env, so let's check # PERF: if...in is faster than using env.get(...) if 'QUERY_STRING' in env and env['QUERY_STRING']: # TODO(kgriffs): Should this escape individual values instead # of the entire string? The way it is now, this: # # x=ab%2Bcd%3D42%2C9 # # becomes this: # # x=ab+cd=42,9 # self.query_string = uri.decode(env['QUERY_STRING']) else: self.query_string = six.text_type() # PERF: Don't parse it if we don't have to! if self.query_string: self._params = uri.parse_query_string(self.query_string) else: self._params = {} helpers.normalize_headers(env) self._cached_headers = {} self._cached_uri = None self._cached_relative_uri = None self.content_type = self._get_header_by_wsgi_name('HTTP_CONTENT_TYPE') # NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust, # normalizing semantics between, e.g., gunicorn and wsgiref. if isinstance(self.stream, NativeStream): # pragma: nocover # NOTE(kgriffs): coverage can't detect that this *is* actually # covered since the test that does so uses multiprocessing. self.stream = helpers.Body(self.stream, self.content_length) # PERF(kgriffs): Technically, we should spend a few more # cycles and parse the content type for real, but # this heuristic will work virtually all the time. if (self.content_type and 'application/x-www-form-urlencoded' in self.content_type): # NOTE(kgriffs): This assumes self.stream has been patched # above in the case of wsgiref, so that self.content_length # is not needed. Normally we just avoid accessing # self.content_length, because it is a little expensive # to call. We could cache self.content_length, but the # overhead to do that won't usually be helpful, since # content length will only ever be read once per # request in most cases. body = self.stream.read() body = body.decode('ascii') extra_params = uri.parse_query_string(uri.decode(body)) self._params.update(extra_params)
def __init__(self, scope, receive, options=None): # ===================================================================== # Prepare headers # ===================================================================== req_headers = {} for header_name, header_value in scope['headers']: # NOTE(kgriffs): According to ASGI 3.0, header names are always # lowercased, and both name and value are byte strings. Although # technically header names and values are restricted to US-ASCII # we decode using the default 'utf-8' because it is a little # faster than passing an encoding option. header_name = header_name.decode() header_value = header_value.decode() # NOTE(kgriffs): There are no standard request headers that # allow multiple instances to appear in the request while also # disallowing list syntax. if header_name not in req_headers or header_name in SINGLETON_HEADERS: req_headers[header_name] = header_value else: req_headers[header_name] += ',' + header_value self._asgi_headers = req_headers # ===================================================================== # Misc. # ===================================================================== self._asgi_server_cached = None # Lazy self.scope = scope self.options = options if options else falcon.request.RequestOptions() self._wsgierrors = None self.method = scope['method'] self.uri_template = None self._media = None # TODO(kgriffs): ASGI does not specify whether 'path' may be empty, # as was allowed for WSGI. path = scope['path'] or '/' if (self.options.strip_url_path_trailing_slash and len(path) != 1 and path.endswith('/')): self.path = path[:-1] else: self.path = path query_string = scope['query_string'].decode() self.query_string = query_string if query_string: self._params = parse_query_string( query_string, keep_blank=self.options.keep_blank_qs_values, csv=self.options.auto_parse_qs_csv, ) else: self._params = {} self._cached_access_route = None self._cached_forwarded = None self._cached_forwarded_prefix = None self._cached_forwarded_uri = None self._cached_headers = req_headers self._cached_prefix = None self._cached_relative_uri = None self._cached_uri = None if self.method == 'GET': # PERF(kgriffs): Normally we expect no Content-Type header, so # use this pattern which is a little bit faster than dict.get() if 'content-type' in req_headers: self.content_type = req_headers['content-type'] else: self.content_type = None else: # PERF(kgriffs): This is the most performant pattern when we expect # the key to be present most of the time. try: self.content_type = req_headers['content-type'] except KeyError: self.content_type = None # ===================================================================== # The request body stream is created lazily # ===================================================================== # NOTE(kgriffs): The ASGI spec states that "you should not trigger # on a connection opening alone". I take this to mean that the app # should have the opportunity to respond with a 401, for example, # without having to first read any of the body. This is accomplished # in Falcon by only reading the first data event when the app attempts # to read from req.stream for the first time, and in uvicorn # (for example) by not confirming a 100 Continue request unless # the app calls receive() to read the request body. self._stream = None self._receive = receive # ===================================================================== # Create a context object # ===================================================================== self.context = self.context_type()
def __init__(self, env, options=None): global _maybe_wrap_wsgi_stream self.env = env self.options = options if options else RequestOptions() if self.context_type is None: # Literal syntax is more efficient than using dict() self.context = {} else: # pylint will detect this as not-callable because it only sees the # declaration of None, not whatever type a subclass may have set. self.context = self.context_type() # pylint: disable=not-callable self._wsgierrors = env['wsgi.errors'] self.stream = env['wsgi.input'] self.method = env['REQUEST_METHOD'] # Normalize path path = env['PATH_INFO'] if path: if len(path) != 1 and path.endswith('/'): self.path = path[:-1] else: self.path = path else: self.path = '/' # PERF(kgriffs): if...in is faster than using env.get(...) if 'QUERY_STRING' in env: self.query_string = env['QUERY_STRING'] if self.query_string: self._params = parse_query_string( self.query_string, keep_blank_qs_values=self.options.keep_blank_qs_values, ) else: self._params = {} else: self.query_string = '' self._params = {} self._cookies = None self._cached_headers = None self._cached_uri = None self._cached_relative_uri = None try: self.content_type = self.env['CONTENT_TYPE'] except KeyError: self.content_type = None # NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust, # normalizing semantics between, e.g., gunicorn and wsgiref. if _maybe_wrap_wsgi_stream: if isinstance(self.stream, NativeStream): # NOTE(kgriffs): This is covered by tests, it's just that # coverage can't figure this out for some reason (TBD). self._wrap_stream() # pragma nocover else: # PERF(kgriffs): If self.stream does not need to be wrapped # this time, it never needs to be wrapped since the server # will continue using the same type for wsgi.input. _maybe_wrap_wsgi_stream = False # PERF(kgriffs): Technically, we should spend a few more # cycles and parse the content type for real, but # this heuristic will work virtually all the time. if (self.content_type is not None and 'application/x-www-form-urlencoded' in self.content_type): self._parse_form_urlencoded()
def urlencoded(body, charset='ascii', **kwargs): """Converts query strings into native Python objects""" return parse_query_string(text(body, charset=charset), False)
def test_parse_query_string_edge_cases(self, query_string, keep_blank, expected): assert uri.parse_query_string(query_string, keep_blank=keep_blank) == (expected)
def __init__(self, env): """Initialize attributes based on a WSGI environment dict Note: Request is not meant to be instantiated directory by responders. Args: env: A WSGI environment dict passed in from the server. See also the PEP-3333 spec. """ self.env = env self._wsgierrors = env['wsgi.errors'] self.stream = env['wsgi.input'] self.method = env['REQUEST_METHOD'] # Normalize path path = env['PATH_INFO'] if path: if len(path) != 1 and path.endswith('/'): self.path = path[:-1] else: self.path = path else: self.path = '/' # QUERY_STRING isn't required to be in env, so let's check # PERF: if...in is faster than using env.get(...) if 'QUERY_STRING' in env and env['QUERY_STRING']: # TODO(kgriffs): Should this escape individual values instead # of the entire string? The way it is now, this: # # x=ab%2Bcd%3D42%2C9 # # becomes this: # # x=ab+cd=42,9 # self.query_string = uri.decode(env['QUERY_STRING']) else: self.query_string = six.text_type() # PERF: Don't parse it if we don't have to! if self.query_string: self._params = uri.parse_query_string(self.query_string) else: self._params = {} helpers.normalize_headers(env) self._cached_headers = {} self._cached_uri = None self._cached_relative_uri = None # NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust, # normalizing semantics between, e.g., gunicorn and wsgiref. if isinstance(self.stream, NativeStream): # pragma: nocover # NOTE(kgriffs): coverage can't detect that this *is* actually # covered since the test that does so uses multiprocessing. self.stream = helpers.Body(self.stream, self.content_length)
def __init__(self, env, options=None): self.env = env self.options = options if options else RequestOptions() self._wsgierrors = env['wsgi.errors'] self.method = env['REQUEST_METHOD'] self.uri_template = None # Normalize path path = env['PATH_INFO'] if path: if six.PY3: # PEP 3333 specifies that PATH_INFO variable are always # "bytes tunneled as latin-1" and must be encoded back path = path.encode('latin1').decode('utf-8', 'replace') if len(path) != 1 and path.endswith('/'): self.path = path[:-1] else: self.path = path else: self.path = '/' # PERF(ueg1990): try/catch cheaper and faster (and more Pythonic) try: self.query_string = env['QUERY_STRING'] except KeyError: self.query_string = '' self._params = {} else: if self.query_string: self._params = parse_query_string( self.query_string, keep_blank_qs_values=self.options.keep_blank_qs_values, parse_qs_csv=self.options.auto_parse_qs_csv, ) else: self._params = {} self._cookies = None self._cached_headers = None self._cached_uri = None self._cached_relative_uri = None self._cached_access_route = None try: self.content_type = self.env['CONTENT_TYPE'] except KeyError: self.content_type = None # NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust, # normalizing semantics between, e.g., gunicorn and wsgiref. if not Request._wsgi_input_type_known: Request._always_wrap_wsgi_input = isinstance( env['wsgi.input'], (NativeStream, InputWrapper) ) Request._wsgi_input_type_known = True if Request._always_wrap_wsgi_input: # TODO(kgriffs): In Falcon 2.0, stop wrapping stream since it is # less useful now that we have bounded_stream. self.stream = self._get_wrapped_wsgi_input() self._bounded_stream = self.stream else: self.stream = env['wsgi.input'] self._bounded_stream = None # Lazy wrapping # PERF(kgriffs): Technically, we should spend a few more # cycles and parse the content type for real, but # this heuristic will work virtually all the time. if ( self.options.auto_parse_form_urlencoded and self.content_type is not None and 'application/x-www-form-urlencoded' in self.content_type and # NOTE(kgriffs): Within HTTP, a payload for a GET or HEAD # request has no defined semantics, so we don't expect a # body in those cases. We would normally not expect a body # for OPTIONS either, but RFC 7231 does allow for it. self.method not in ('GET', 'HEAD') ): self._parse_form_urlencoded() if self.context_type is None: # Literal syntax is more efficient than using dict() self.context = {} else: self.context = self.context_type()
def __init__(self, env, options=None): global _maybe_wrap_wsgi_stream self.env = env self.options = options if options else RequestOptions() self._wsgierrors = env['wsgi.errors'] self.stream = env['wsgi.input'] self.method = env['REQUEST_METHOD'] # Normalize path path = env['PATH_INFO'] if path: if six.PY3: # pragma: no cover # PEP 3333 specifies that PATH_INFO variable are always # "bytes tunneled as latin-1" and must be encoded back path = path.encode('latin1').decode('utf-8', 'replace') if len(path) != 1 and path.endswith('/'): self.path = path[:-1] else: self.path = path else: self.path = '/' # PERF(kgriffs): if...in is faster than using env.get(...) if 'QUERY_STRING' in env: self.query_string = env['QUERY_STRING'] if self.query_string: self._params = parse_query_string( self.query_string, keep_blank_qs_values=self.options.keep_blank_qs_values, ) else: self._params = {} else: self.query_string = '' self._params = {} self._cookies = None self._cached_headers = None self._cached_uri = None self._cached_relative_uri = None self._cached_access_route = None try: self.content_type = self.env['CONTENT_TYPE'] except KeyError: self.content_type = None # NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust, # normalizing semantics between, e.g., gunicorn and wsgiref. if _maybe_wrap_wsgi_stream: if isinstance(self.stream, NativeStream): # NOTE(kgriffs): This is covered by tests, it's just that # coverage can't figure this out for some reason (TBD). self._wrap_stream() # pragma nocover else: # PERF(kgriffs): If self.stream does not need to be wrapped # this time, it never needs to be wrapped since the server # will continue using the same type for wsgi.input. _maybe_wrap_wsgi_stream = False # PERF(kgriffs): Technically, we should spend a few more # cycles and parse the content type for real, but # this heuristic will work virtually all the time. if (self.content_type is not None and 'application/x-www-form-urlencoded' in self.content_type): self._parse_form_urlencoded() if self.context_type is None: # Literal syntax is more efficient than using dict() self.context = {} else: # pylint will detect this as not-callable because it only sees the # declaration of None, not whatever type a subclass may have set. self.context = self.context_type() # pylint: disable=not-callable
def __init__(self, env, options=None): self.env = env self.options = options if options else RequestOptions() self._wsgierrors = env['wsgi.errors'] self.method = env['REQUEST_METHOD'] self.uri_template = None # Normalize path path = env['PATH_INFO'] if path: if six.PY3: # PEP 3333 specifies that PATH_INFO variable are always # "bytes tunneled as latin-1" and must be encoded back path = path.encode('latin1').decode('utf-8', 'replace') if len(path) != 1 and path.endswith('/'): self.path = path[:-1] else: self.path = path else: self.path = '/' # PERF(ueg1990): try/catch cheaper and faster (and more Pythonic) try: self.query_string = env['QUERY_STRING'] except KeyError: self.query_string = '' self._params = {} else: if self.query_string: self._params = parse_query_string( self.query_string, keep_blank_qs_values=self.options.keep_blank_qs_values, parse_qs_csv=self.options.auto_parse_qs_csv, ) else: self._params = {} self._cookies = None self._cached_headers = None self._cached_uri = None self._cached_relative_uri = None self._cached_access_route = None try: self.content_type = self.env['CONTENT_TYPE'] except KeyError: self.content_type = None # NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust, # normalizing semantics between, e.g., gunicorn and wsgiref. if not Request._wsgi_input_type_known: Request._always_wrap_wsgi_input = isinstance( env['wsgi.input'], (NativeStream, InputWrapper) ) Request._wsgi_input_type_known = True if Request._always_wrap_wsgi_input: # TODO(kgriffs): In Falcon 2.0, stop wrapping stream since it is # less useful now that we have bounded_stream. self.stream = self._get_wrapped_wsgi_input() self._bounded_stream = self.stream else: self.stream = env['wsgi.input'] self._bounded_stream = None # Lazy wrapping # PERF(kgriffs): Technically, we should spend a few more # cycles and parse the content type for real, but # this heuristic will work virtually all the time. if (self.options.auto_parse_form_urlencoded and self.content_type is not None and 'application/x-www-form-urlencoded' in self.content_type and self.method == 'POST'): self._parse_form_urlencoded() if self.context_type is None: # Literal syntax is more efficient than using dict() self.context = {} else: self.context = self.context_type()
def __init__(self, env): self.env = env if self.context_type is None: # Literal syntax is more efficient than using dict() self.context = {} else: # pylint will detect this as not-callable because it only sees the # declaration of None, not whatever type a subclass may have set. self.context = self.context_type() # pylint: disable=not-callable self._wsgierrors = env['wsgi.errors'] self.stream = env['wsgi.input'] self.method = env['REQUEST_METHOD'] # Normalize path path = env['PATH_INFO'] if path: if len(path) != 1 and path.endswith('/'): self.path = path[:-1] else: self.path = path else: self.path = '/' # QUERY_STRING isn't required to be in env, so let's check # PERF: if...in is faster than using env.get(...) if 'QUERY_STRING' in env and env['QUERY_STRING']: # TODO(kgriffs): Should this escape individual values instead # of the entire string? The way it is now, this: # # x=ab%2Bcd%3D42%2C9 # # becomes this: # # x=ab+cd=42,9 # self.query_string = uri.decode(env['QUERY_STRING']) else: self.query_string = six.text_type() # PERF: Don't parse it if we don't have to! if self.query_string: self._params = uri.parse_query_string(self.query_string) else: self._params = {} helpers.normalize_headers(env) self._cached_headers = {} self._cached_uri = None self._cached_relative_uri = None self.content_type = self._get_header_by_wsgi_name('HTTP_CONTENT_TYPE') # NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust, # normalizing semantics between, e.g., gunicorn and wsgiref. if isinstance(self.stream, NativeStream): # pragma: nocover # NOTE(kgriffs): coverage can't detect that this *is* actually # covered since the test that does so uses multiprocessing. self.stream = helpers.Body(self.stream, self.content_length) # PERF(kgriffs): Technically, we should spend a few more # cycles and parse the content type for real, but # this heuristic will work virtually all the time. if (self.content_type and 'application/x-www-form-urlencoded' in self.content_type): # NOTE(kgriffs): This assumes self.stream has been patched # above in the case of wsgiref, so that self.content_length # is not needed. Normally we just avoid accessing # self.content_length, because it is a little expensive # to call. We could cache self.content_length, but the # overhead to do that won't usually be helpful, since # content length will only ever be read once per # request in most cases. body = self.stream.read() body = body.decode('ascii') extra_params = uri.parse_query_string(uri.decode(body)) self._params.update(extra_params)