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.*
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
$ http --session user1 -a user1:password example.org X-Foo:Bar
Now you can refer to the session by its name:
.. 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
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
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')
misc.add_argument(
sessions = parser.add_argument_group(title='Sessions')\
.add_mutually_exclusive_group(required=False)
sessions.add_argument(
'--session', metavar='SESSION_NAME',
help=_('''
Create or reuse a session.
Create, or reuse and update a session.
Withing a session, custom headers, auth credential, as well as any
cookies sent by the server persist between requests.
You can use the `httpie' management command to manipulate
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):
"""Send the request and return a `request.Response`."""
requests_kwargs = get_requests_kwargs(args)
@ -23,14 +24,18 @@ def get_response(args):
sys.stderr.write(
'\n>>> requests.request(%s)\n\n' % pformat(requests_kwargs))
if args.session:
return sessions.get_response(args.session, requests_kwargs)
else:
if not args.session and not args.session_read:
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):
"""Send the request and return a `request.Response`."""
"""Translate our `args` into `requests.request` keyword arguments."""
base_headers = defaults['base_headers'].copy()
base_headers['User-Agent'] = DEFAULT_UA

View File

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