Added --session-read for read-only sessions.

This commit is contained in:
Jakub Roztocil 2012-09-07 12:38:52 +02:00
parent da0eb7db79
commit 316e3f45a9
4 changed files with 53 additions and 23 deletions

View File

@ -509,13 +509,12 @@ Sessions
*NOTE: This is an experimental feature. Feedback appretiated.* *NOTE: This is an experimental feature. Feedback appretiated.*
HTTPie supports named, per-host sessions, where custom headers, authorization, HTTPie supports named, per-host sessions, where custom headers, authorization,
and cookies sent by the server persist between requests: and cookies (manually specified or sent by the server) persist between requests:
.. code-block:: bash .. code-block:: bash
$ http --session user1 -a user1:password example.org X-Foo:Bar $ http --session user1 -a user1:password example.org X-Foo:Bar
Now you can refer to the session by its name: Now you can refer to the session by its name:
.. code-block:: bash .. code-block:: bash
@ -529,6 +528,9 @@ To switch to another session simple pass a different name:
$ http --session user2 -a user2:password example.org X-Bar:Foo $ http --session user2 -a user2:password example.org X-Bar:Foo
To use an existing session without updating it from the request/response
exchange, specify the session via ``--session-read=SESSION_NAME`` instead.
You can view and manipulate existing sessions via the ``httpie`` management You can view and manipulate existing sessions via the ``httpie`` management
command, see ``httpie --help``. command, see ``httpie --help``.

View File

@ -219,19 +219,25 @@ output_options.add_argument('--stream', '-S', action='store_true', default=False
############################################################################### ###############################################################################
# Misc # Sessions
############################################################################### ###############################################################################
misc = parser.add_argument_group(title='Sessions') sessions = parser.add_argument_group(title='Sessions')\
misc.add_argument( .add_mutually_exclusive_group(required=False)
sessions.add_argument(
'--session', metavar='SESSION_NAME', '--session', metavar='SESSION_NAME',
help=_(''' help=_('''
Create or reuse a session. Create, or reuse and update a session.
Withing a session, custom headers, auth credential, as well as any Withing a session, custom headers, auth credential, as well as any
cookies sent by the server persist between requests. cookies sent by the server persist between requests.
You can use the `httpie' management command to manipulate You can use the `httpie' management command to manipulate
and inspect existing sessions. See `httpie --help'. and inspect existing sessions. See `httpie --help'.
''') ''')
) )
sessions.add_argument(
'--session-read', metavar='SESSION_NAME',
help=_('''Create or reuse a session, but do not update it once saved.''')
)
############################################################################### ###############################################################################

View File

@ -16,6 +16,7 @@ DEFAULT_UA = 'HTTPie/%s' % __version__
def get_response(args): def get_response(args):
"""Send the request and return a `request.Response`."""
requests_kwargs = get_requests_kwargs(args) requests_kwargs = get_requests_kwargs(args)
@ -23,14 +24,18 @@ def get_response(args):
sys.stderr.write( sys.stderr.write(
'\n>>> requests.request(%s)\n\n' % pformat(requests_kwargs)) '\n>>> requests.request(%s)\n\n' % pformat(requests_kwargs))
if args.session: if not args.session and not args.session_read:
return sessions.get_response(args.session, requests_kwargs)
else:
return requests.request(**requests_kwargs) return requests.request(**requests_kwargs)
else:
return sessions.get_response(
name=args.session or args.session_read,
request_kwargs=requests_kwargs,
read_only=bool(args.session_read),
)
def get_requests_kwargs(args): def get_requests_kwargs(args):
"""Send the request and return a `request.Response`.""" """Translate our `args` into `requests.request` keyword arguments."""
base_headers = defaults['base_headers'].copy() base_headers = defaults['base_headers'].copy()
base_headers['User-Agent'] = DEFAULT_UA base_headers['User-Agent'] = DEFAULT_UA

View File

@ -10,10 +10,11 @@ import codecs
import shutil import shutil
import subprocess import subprocess
import requests
from requests.compat import urlparse from requests.compat import urlparse
from requests import Session as RSession
from requests.cookies import RequestsCookieJar, create_cookie from requests.cookies import RequestsCookieJar, create_cookie
from requests.auth import HTTPBasicAuth, HTTPDigestAuth from requests.auth import HTTPBasicAuth, HTTPDigestAuth
from argparse import OPTIONAL
from.import __version__ from.import __version__
from.config import CONFIG_DIR from.config import CONFIG_DIR
@ -23,7 +24,11 @@ from.output import PygmentsProcessor
SESSIONS_DIR = os.path.join(CONFIG_DIR, 'sessions') SESSIONS_DIR = os.path.join(CONFIG_DIR, 'sessions')
def get_response(name, request_kwargs): def get_response(name, request_kwargs, read_only=False):
"""Like `client.get_response`, but applies permanent
aspects of the session to the request.
"""
host = Host(request_kwargs['headers'].get('Host', None) host = Host(request_kwargs['headers'].get('Host', None)
or urlparse(request_kwargs['url']).netloc.split('@')[-1]) or urlparse(request_kwargs['url']).netloc.split('@')[-1])
@ -41,22 +46,26 @@ def get_response(name, request_kwargs):
elif session.auth: elif session.auth:
request_kwargs['auth'] = session.auth request_kwargs['auth'] = session.auth
rsession = RSession(cookies=session.cookies) rsession = requests.Session(cookies=session.cookies)
try: try:
response = rsession.request(**request_kwargs) response = rsession.request(**request_kwargs)
except Exception: except Exception:
raise raise
else: else:
session.cookies = rsession.cookies if not read_only or session.is_new:
session.save() session.cookies = rsession.cookies
session.save()
return response return response
class Host(object): class Host(object):
"""A host is a per-host directory on the disk containing sessions files."""
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
def __iter__(self): def __iter__(self):
"""Return a iterator yielding `(session_name, session_path)`."""
for fn in sorted(glob.glob1(self.path, '*.json')): for fn in sorted(glob.glob1(self.path, '*.json')):
yield os.path.splitext(fn)[0], os.path.join(self.path, fn) yield os.path.splitext(fn)[0], os.path.join(self.path, fn)
@ -78,12 +87,15 @@ class Host(object):
@classmethod @classmethod
def all(cls): def all(cls):
"""Return a generator yielding a host at a time."""
for name in sorted(glob.glob1(SESSIONS_DIR, '*')): for name in sorted(glob.glob1(SESSIONS_DIR, '*')):
if os.path.isdir(os.path.join(SESSIONS_DIR, name)): if os.path.isdir(os.path.join(SESSIONS_DIR, name)):
yield Host(name) yield Host(name)
class Session(dict): class Session(dict):
""""""
def __init__(self, host, name, *args, **kwargs): def __init__(self, host, name, *args, **kwargs):
super(Session, self).__init__(*args, **kwargs) super(Session, self).__init__(*args, **kwargs)
self.host = host self.host = host
@ -91,10 +103,6 @@ class Session(dict):
self['headers'] = {} self['headers'] = {}
self['cookies'] = {} self['cookies'] = {}
@property
def path(self):
return os.path.join(self.host.path, self.name + '.json')
def load(self): def load(self):
try: try:
with open(self.path, 'rt') as f: with open(self.path, 'rt') as f:
@ -121,6 +129,14 @@ class Session(dict):
if e.errno != errno.ENOENT: if e.errno != errno.ENOENT:
raise raise
@property
def path(self):
return os.path.join(self.host.path, self.name + '.json')
@property
def is_new(self):
return not os.path.exists(self.path)
@property @property
def cookies(self): def cookies(self):
jar = RequestsCookieJar() jar = RequestsCookieJar()
@ -163,7 +179,7 @@ class Session(dict):
HTTPDigestAuth: 'digest'}[type(cred)], HTTPDigestAuth: 'digest'}[type(cred)],
'username': cred.username, 'username': cred.username,
'password': cred.password, 'password': cred.password,
} }
def list_command(args): def list_command(args):
@ -211,13 +227,14 @@ def edit_command(args):
def add_commands(subparsers): def add_commands(subparsers):
# List # List
list_ = subparsers.add_parser('session-list', help='list sessions') list_ = subparsers.add_parser('session-list', help='list sessions')
list_.set_defaults(command=list_command) list_.set_defaults(command=list_command)
list_.add_argument('host', nargs='?') list_.add_argument('host', nargs=OPTIONAL)
# Show # Show
show = subparsers.add_parser('session-show', help='list or show sessions') show = subparsers.add_parser('session-show', help='show a session')
show.set_defaults(command=show_command) show.set_defaults(command=show_command)
show.add_argument('host') show.add_argument('host')
show.add_argument('name') show.add_argument('name')
@ -233,6 +250,6 @@ def add_commands(subparsers):
delete = subparsers.add_parser('session-delete', help='delete a session') delete = subparsers.add_parser('session-delete', help='delete a session')
delete.set_defaults(command=delete_command) delete.set_defaults(command=delete_command)
delete.add_argument('host') delete.add_argument('host')
delete.add_argument('name', nargs='?', delete.add_argument('name', nargs=OPTIONAL,
help='The name of the session to be deleted.' help='The name of the session to be deleted.'
' If not specified, all host sessions are deleted.') ' If not specified, all host sessions are deleted.')