Imported from SVN by Bitbucket
This commit is contained in:
189
PasteScript-1.7.4.2-py2.6.egg/paste/script/request.py
Executable file
189
PasteScript-1.7.4.2-py2.6.egg/paste/script/request.py
Executable file
@@ -0,0 +1,189 @@
|
||||
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
|
||||
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import urlparse
|
||||
import urllib
|
||||
from command import Command, BadCommand
|
||||
from paste.deploy import loadapp, loadserver
|
||||
from paste.wsgilib import raw_interactive
|
||||
|
||||
class RequestCommand(Command):
|
||||
|
||||
min_args = 2
|
||||
usage = 'CONFIG_FILE URL [OPTIONS/ARGUMENTS]'
|
||||
takes_config_file = 1
|
||||
summary = "Run a request for the described application"
|
||||
description = """\
|
||||
This command makes an artifical request to a web application that
|
||||
uses a paste.deploy configuration file for the server and
|
||||
application.
|
||||
|
||||
Use 'paster request config.ini /url' to request /url. Use
|
||||
'paster post config.ini /url < data' to do a POST with the given
|
||||
request body.
|
||||
|
||||
If the URL is relative (doesn't begin with /) it is interpreted as
|
||||
relative to /.command/. The variable environ['paste.command_request']
|
||||
will be set to True in the request, so your application can distinguish
|
||||
these calls from normal requests.
|
||||
|
||||
Note that you can pass options besides the options listed here; any unknown
|
||||
options will be passed to the application in environ['QUERY_STRING'].
|
||||
"""
|
||||
|
||||
parser = Command.standard_parser(quiet=True)
|
||||
parser.add_option('-n', '--app-name',
|
||||
dest='app_name',
|
||||
metavar='NAME',
|
||||
help="Load the named application (default main)")
|
||||
parser.add_option('--config-var',
|
||||
dest='config_vars',
|
||||
metavar='NAME:VALUE',
|
||||
action='append',
|
||||
help="Variable to make available in the config for %()s substitution "
|
||||
"(you can use this option multiple times)")
|
||||
parser.add_option('--header',
|
||||
dest='headers',
|
||||
metavar='NAME:VALUE',
|
||||
action='append',
|
||||
help="Header to add to request (you can use this option multiple times)")
|
||||
parser.add_option('--display-headers',
|
||||
dest='display_headers',
|
||||
action='store_true',
|
||||
help='Display headers before the response body')
|
||||
|
||||
ARG_OPTIONS = ['-n', '--app-name', '--config-var', '--header']
|
||||
OTHER_OPTIONS = ['--display-headers']
|
||||
|
||||
## FIXME: some kind of verbosity?
|
||||
## FIXME: allow other methods than POST and GET?
|
||||
|
||||
_scheme_re = re.compile(r'^[a-z][a-z]+:', re.I)
|
||||
|
||||
def command(self):
|
||||
vars = {}
|
||||
app_spec = self.args[0]
|
||||
url = self.args[1]
|
||||
url = urlparse.urljoin('/.command/', url)
|
||||
if self.options.config_vars:
|
||||
for item in self.option.config_vars:
|
||||
if ':' not in item:
|
||||
raise BadCommand(
|
||||
"Bad option, should be name:value : --config-var=%s" % item)
|
||||
name, value = item.split(':', 1)
|
||||
vars[name] = value
|
||||
headers = {}
|
||||
if self.options.headers:
|
||||
for item in self.options.headers:
|
||||
if ':' not in item:
|
||||
raise BadCommand(
|
||||
"Bad option, should be name:value : --header=%s" % item)
|
||||
name, value = item.split(':', 1)
|
||||
headers[name] = value.strip()
|
||||
if not self._scheme_re.search(app_spec):
|
||||
app_spec = 'config:'+app_spec
|
||||
if self.options.app_name:
|
||||
if '#' in app_spec:
|
||||
app_spec = app_spec.split('#', 1)[0]
|
||||
app_spec = app_spec + '#' + options.app_name
|
||||
app = loadapp(app_spec, relative_to=os.getcwd(), global_conf=vars)
|
||||
if self.command_name.lower() == 'post':
|
||||
request_method = 'POST'
|
||||
else:
|
||||
request_method = 'GET'
|
||||
qs = []
|
||||
for item in self.args[2:]:
|
||||
if '=' in item:
|
||||
item = urllib.quote(item.split('=', 1)[0]) + '=' + urllib.quote(item.split('=', 1)[1])
|
||||
else:
|
||||
item = urllib.quote(item)
|
||||
qs.append(item)
|
||||
qs = '&'.join(qs)
|
||||
|
||||
environ = {
|
||||
'REQUEST_METHOD': request_method,
|
||||
## FIXME: shouldn't be static (an option?):
|
||||
'CONTENT_TYPE': 'text/plain',
|
||||
'wsgi.run_once': True,
|
||||
'wsgi.multithread': False,
|
||||
'wsgi.multiprocess': False,
|
||||
'wsgi.errors': sys.stderr,
|
||||
'QUERY_STRING': qs,
|
||||
'HTTP_ACCEPT': 'text/plain;q=1.0, */*;q=0.1',
|
||||
'paste.command_request': True,
|
||||
}
|
||||
if request_method == 'POST':
|
||||
environ['wsgi.input'] = sys.stdin
|
||||
environ['CONTENT_LENGTH'] = '-1'
|
||||
for name, value in headers.items():
|
||||
if name.lower() == 'content-type':
|
||||
name = 'CONTENT_TYPE'
|
||||
else:
|
||||
name = 'HTTP_'+name.upper().replace('-', '_')
|
||||
environ[name] = value
|
||||
|
||||
status, headers, output, errors = raw_interactive(app, url, **environ)
|
||||
assert not errors, "errors should be printed directly to sys.stderr"
|
||||
if self.options.display_headers:
|
||||
for name, value in headers:
|
||||
sys.stdout.write('%s: %s\n' % (name, value))
|
||||
sys.stdout.write('\n')
|
||||
sys.stdout.write(output)
|
||||
sys.stdout.flush()
|
||||
status_int = int(status.split()[0])
|
||||
if status_int != 200:
|
||||
return status_int
|
||||
|
||||
def parse_args(self, args):
|
||||
if args == ['-h']:
|
||||
Command.parse_args(self, args)
|
||||
return
|
||||
# These are the arguments parsed normally:
|
||||
normal_args = []
|
||||
# And these are arguments passed to the URL:
|
||||
extra_args = []
|
||||
# This keeps track of whether we have the two required positional arguments:
|
||||
pos_args = 0
|
||||
while args:
|
||||
start = args[0]
|
||||
if not start.startswith('-'):
|
||||
if pos_args < 2:
|
||||
pos_args += 1
|
||||
normal_args.append(start)
|
||||
args.pop(0)
|
||||
continue
|
||||
else:
|
||||
normal_args.append(start)
|
||||
args.pop(0)
|
||||
continue
|
||||
else:
|
||||
found = False
|
||||
for option in self.ARG_OPTIONS:
|
||||
if start == option:
|
||||
normal_args.append(start)
|
||||
args.pop(0)
|
||||
if not args:
|
||||
raise BadCommand(
|
||||
"Option %s takes an argument" % option)
|
||||
normal_args.append(args.pop(0))
|
||||
found = True
|
||||
break
|
||||
elif start.startswith(option+'='):
|
||||
normal_args.append(start)
|
||||
args.pop(0)
|
||||
found = True
|
||||
break
|
||||
if found:
|
||||
continue
|
||||
if start in self.OTHER_OPTIONS:
|
||||
normal_args.append(start)
|
||||
args.pop(0)
|
||||
continue
|
||||
extra_args.append(start)
|
||||
args.pop(0)
|
||||
Command.parse_args(self, normal_args)
|
||||
# Add the extra arguments back in:
|
||||
self.args = self.args + extra_args
|
||||
|
||||
Reference in New Issue
Block a user