diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 222ec90c..126f4128 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,11 +14,12 @@ This project adheres to `Semantic Versioning `_. * Added ``--max-headers`` to allow setting the max header limit. * Added ``--compress``. * Added ``https`` alias command with ``https://`` as the default scheme. -* Fixed an exception when ``stdin`` was a closed fd. +* Fixed an error when ``stdin`` was a closed fd. +* Fixed an error when the config directory was not writeable. `1.0.3`_ (2019-08-26) -------------------------- +--------------------- * Fixed CVE-2019-10751 — the way the output filename is generated for ``--download`` requests without ``--output`` resulting in a redirect has diff --git a/httpie/config.py b/httpie/config.py index 06ce586b..57a4f731 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -55,7 +55,7 @@ class BaseConfigDict(dict): if e.errno != errno.ENOENT: raise - def save(self): + def save(self, fail_silently=False): self['__meta__'] = { 'httpie': __version__ } @@ -65,9 +65,13 @@ class BaseConfigDict(dict): if self.about: self['__meta__']['about'] = self.about - with open(self.path, 'w') as f: - json.dump(self, f, indent=4, sort_keys=True, ensure_ascii=True) - f.write('\n') + try: + with open(self.path, 'w') as f: + json.dump(self, f, indent=4, sort_keys=True, ensure_ascii=True) + f.write('\n') + except IOError: + if not fail_silently: + raise def delete(self): try: @@ -92,21 +96,5 @@ class Config(BaseConfigDict): self.update(self.DEFAULTS) self.directory = directory - def load(self): - super(Config, self).load() - self._migrate_implicit_content_type() - def _get_path(self): return os.path.join(self.directory, self.name + '.json') - - def _migrate_implicit_content_type(self): - """Migrate the removed implicit_content_type config option""" - try: - implicit_content_type = self.pop('implicit_content_type') - except KeyError: - self.save() - else: - if implicit_content_type == 'form': - self['default_options'].insert(0, '--form') - self.save() - self.load() diff --git a/httpie/context.py b/httpie/context.py index 621fdfa5..2f245378 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -82,7 +82,7 @@ class Environment(object): if not hasattr(self, '_config'): self._config = Config(directory=self.config_dir) if self._config.is_new(): - self._config.save() + self._config.save(fail_silently=True) else: self._config.load() return self._config diff --git a/tests/test_config.py b/tests/test_config.py index d31ae1f3..63bb4504 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,5 +1,5 @@ from httpie import __version__ -from utils import MockEnvironment, http +from utils import MockEnvironment, http, HTTP_OK from httpie.context import Environment @@ -11,6 +11,14 @@ def test_default_options(httpbin): assert r.json['form'] == {"foo": "bar"} +def test_config_dir_not_writeable(httpbin): + r = http(httpbin + '/get', env=MockEnvironment( + config_dir='/', + create_temp_config_dir=False, + )) + assert HTTP_OK in r + + def test_default_options_overwrite(httpbin): env = MockEnvironment() env.config['default_options'] = ['--form'] @@ -19,22 +27,6 @@ def test_default_options_overwrite(httpbin): assert r.json['json'] == {"foo": "bar"} -def test_migrate_implicit_content_type(): - config = MockEnvironment().config - - config['implicit_content_type'] = 'json' - config.save() - config.load() - assert 'implicit_content_type' not in config - assert not config['default_options'] - - config['implicit_content_type'] = 'form' - config.save() - config.load() - assert 'implicit_content_type' not in config - assert config['default_options'] == ['--form'] - - def test_current_version(): version = Environment().config['__meta__']['httpie'] assert version == __version__ diff --git a/tests/utils.py b/tests/utils.py index aa16f906..0412791b 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -39,7 +39,8 @@ class MockEnvironment(Environment): stdout_isatty = True is_windows = False - def __init__(self, **kwargs): + def __init__(self, create_temp_config_dir=True, **kwargs): + self.create_temp_config_dir = create_temp_config_dir if 'stdout' not in kwargs: kwargs['stdout'] = tempfile.TemporaryFile( mode='w+b', @@ -55,7 +56,8 @@ class MockEnvironment(Environment): @property def config(self): - if not self.config_dir.startswith(tempfile.gettempdir()): + if (self.create_temp_config_dir + and not self.config_dir.startswith(tempfile.gettempdir())): self.config_dir = mk_config_dir() self._delete_config_dir = True return super(MockEnvironment, self).config