atomhttp 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- atomhttp/__init__.py +76 -0
- atomhttp/adapters/__init__.py +4 -0
- atomhttp/adapters/http_adapter.py +102 -0
- atomhttp/adapters/mock_adapter.py +130 -0
- atomhttp/auth/__init__.py +4 -0
- atomhttp/auth/basic_auth.py +90 -0
- atomhttp/auth/bearer_auth.py +83 -0
- atomhttp/client.py +577 -0
- atomhttp/core/__init__.py +19 -0
- atomhttp/core/adapters.py +687 -0
- atomhttp/core/config.py +186 -0
- atomhttp/core/defaults.py +212 -0
- atomhttp/core/form_data.py +282 -0
- atomhttp/core/request.py +240 -0
- atomhttp/core/response.py +101 -0
- atomhttp/errors/__init__.py +13 -0
- atomhttp/errors/http_errors.py +142 -0
- atomhttp/interceptors/__init__.py +5 -0
- atomhttp/interceptors/manager.py +136 -0
- atomhttp/interceptors/request_interceptor.py +18 -0
- atomhttp/interceptors/response_interceptor.py +18 -0
- atomhttp/progress/__init__.py +3 -0
- atomhttp/progress/upload_progress.py +89 -0
- atomhttp/transforms/__init__.py +5 -0
- atomhttp/transforms/data_serializer.py +96 -0
- atomhttp/transforms/request_transform.py +96 -0
- atomhttp/transforms/response_transform.py +73 -0
- atomhttp/utils/__init__.py +5 -0
- atomhttp/utils/cookies.py +128 -0
- atomhttp/utils/helpers.py +111 -0
- atomhttp/utils/redirect.py +107 -0
- atomhttp-1.0.0.dist-info/METADATA +165 -0
- atomhttp-1.0.0.dist-info/RECORD +36 -0
- atomhttp-1.0.0.dist-info/WHEEL +5 -0
- atomhttp-1.0.0.dist-info/licenses/LICENSE +21 -0
- atomhttp-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Redirect Handler Module
|
|
3
|
+
-----------------------
|
|
4
|
+
Handles HTTP redirect responses for the AtomHTTP client.
|
|
5
|
+
|
|
6
|
+
This module provides the RedirectHandler class which manages redirect
|
|
7
|
+
following logic, including checking redirect status codes, tracking
|
|
8
|
+
redirect counts, and constructing absolute URLs from relative redirect
|
|
9
|
+
locations.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from typing import Optional
|
|
13
|
+
from urllib.parse import urlparse, urlunparse
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RedirectHandler:
|
|
17
|
+
"""
|
|
18
|
+
Handle HTTP redirect responses and manage redirect limits.
|
|
19
|
+
|
|
20
|
+
This class tracks the number of redirects followed and provides
|
|
21
|
+
utilities for determining when to follow redirects and how to
|
|
22
|
+
construct absolute redirect URLs from relative locations.
|
|
23
|
+
|
|
24
|
+
The handler supports standard HTTP redirect status codes:
|
|
25
|
+
- 301: Moved Permanently
|
|
26
|
+
- 302: Found (Temporary Redirect)
|
|
27
|
+
- 303: See Other
|
|
28
|
+
- 307: Temporary Redirect
|
|
29
|
+
- 308: Permanent Redirect
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
max_redirects (int): Maximum number of redirects to follow
|
|
33
|
+
redirect_count (int): Current count of redirects followed
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, max_redirects: int = 5):
|
|
37
|
+
"""
|
|
38
|
+
Initialize redirect handler with maximum redirect limit.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
max_redirects (int): Maximum number of redirects to follow.
|
|
42
|
+
Defaults to 5, which is the standard for
|
|
43
|
+
most HTTP clients.
|
|
44
|
+
"""
|
|
45
|
+
self.max_redirects = max_redirects
|
|
46
|
+
self.redirect_count = 0
|
|
47
|
+
|
|
48
|
+
def should_redirect(self, status_code: int) -> bool:
|
|
49
|
+
"""
|
|
50
|
+
Determine if a status code indicates a redirect response.
|
|
51
|
+
|
|
52
|
+
This method checks if the HTTP status code is one of the standard
|
|
53
|
+
redirect codes that should be followed automatically.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
status_code (int): HTTP status code from response
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
bool: True if status code is a redirect (301, 302, 303, 307, 308),
|
|
60
|
+
False otherwise
|
|
61
|
+
"""
|
|
62
|
+
return status_code in (301, 302, 303, 307, 308)
|
|
63
|
+
|
|
64
|
+
def is_max_reached(self) -> bool:
|
|
65
|
+
"""
|
|
66
|
+
Check if the maximum number of redirects has been reached.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
bool: True if redirect_count >= max_redirects, False otherwise
|
|
70
|
+
|
|
71
|
+
Note:
|
|
72
|
+
When this returns True, the client should stop following
|
|
73
|
+
redirects to avoid infinite loops.
|
|
74
|
+
"""
|
|
75
|
+
return self.redirect_count >= self.max_redirects
|
|
76
|
+
|
|
77
|
+
def get_redirect_url(self, location: str, original_url: str) -> str:
|
|
78
|
+
"""
|
|
79
|
+
Convert a redirect location header to an absolute URL.
|
|
80
|
+
|
|
81
|
+
The Location header in HTTP redirects may be either absolute
|
|
82
|
+
(complete URL) or relative (path only). This method resolves
|
|
83
|
+
relative locations to absolute URLs using the original request URL.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
location (str): The Location header value from redirect response
|
|
87
|
+
original_url (str): The original URL that was requested
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
str: Absolute URL to redirect to
|
|
91
|
+
"""
|
|
92
|
+
# If location is already absolute, return it directly
|
|
93
|
+
if location.startswith(('http://', 'https://')):
|
|
94
|
+
return location
|
|
95
|
+
|
|
96
|
+
# Parse the original URL to extract scheme and host
|
|
97
|
+
parsed = urlparse(original_url)
|
|
98
|
+
base = f"{parsed.scheme}://{parsed.netloc}"
|
|
99
|
+
|
|
100
|
+
# Handle absolute path (starts with '/')
|
|
101
|
+
if location.startswith('/'):
|
|
102
|
+
return base + location
|
|
103
|
+
|
|
104
|
+
# Handle relative path (no leading '/')
|
|
105
|
+
# Remove the last segment from the original path to get directory
|
|
106
|
+
path = parsed.path.rsplit('/', 1)[0]
|
|
107
|
+
return base + path + '/' + location
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: atomhttp
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Professional asynchronous HTTP client for Python — interceptors, progress tracking, FormData, Blob, concurrent requests, and full type hints
|
|
5
|
+
Author-email: Abolfazl Hosseini <tryuzr@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/inject3r/atomhttp
|
|
8
|
+
Project-URL: Repository, https://github.com/inject3r/atomhttp.git
|
|
9
|
+
Project-URL: Documentation, https://inject3r.github.io/atomhttp
|
|
10
|
+
Project-URL: Issues, https://github.com/inject3r/atomhttp/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/inject3r/atomhttp/releases
|
|
12
|
+
Keywords: http,client,async,await,aiohttp,rest,api,interceptor,progress,formdata
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
21
|
+
Classifier: Operating System :: OS Independent
|
|
22
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
23
|
+
Classifier: Intended Audience :: Developers
|
|
24
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Classifier: Framework :: AsyncIO
|
|
27
|
+
Requires-Python: >=3.8
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: black>=22.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: isort>=5.10.0; extra == "dev"
|
|
37
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
39
|
+
Provides-Extra: test
|
|
40
|
+
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
41
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
|
|
42
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "test"
|
|
43
|
+
Provides-Extra: all
|
|
44
|
+
Requires-Dist: aiohttp>=3.8.0; extra == "all"
|
|
45
|
+
Requires-Dist: pytest>=7.0.0; extra == "all"
|
|
46
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "all"
|
|
47
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "all"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
<p align="center">
|
|
51
|
+
<img src="https://inject3r.github.io/atomhttp/logo.jpg" alt="AtomHTTP Logo" width="350">
|
|
52
|
+
</p>
|
|
53
|
+
|
|
54
|
+
# AtomHTTP
|
|
55
|
+
|
|
56
|
+
A professional, feature-rich asynchronous HTTP client for Python — designed for developers who need reliability, flexibility, and performance.
|
|
57
|
+
|
|
58
|
+
**[Full Documentation](https://inject3r.github.io/atomhttp)** — Complete API reference, advanced guides, and examples
|
|
59
|
+
|
|
60
|
+
<br/>
|
|
61
|
+
|
|
62
|
+
## Features
|
|
63
|
+
|
|
64
|
+
- **Full HTTP Method Support**: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS with async/await syntax
|
|
65
|
+
- **Request & Response Interceptors**: Modify requests before sending and responses before returning
|
|
66
|
+
- **Upload & Download Progress Tracking**: Real-time callbacks for monitoring data transfer
|
|
67
|
+
- **FormData Support**: Multipart/form-data and URL-encoded form handling with file uploads
|
|
68
|
+
- **Multiple Response Types**: JSON (auto-parsed), text, blob, arraybuffer, and stream
|
|
69
|
+
- **Concurrent Request Helpers**: Execute multiple requests in parallel with `all()` and `spread()`
|
|
70
|
+
- **Base URL Configuration**: Set a base URL once and use relative paths
|
|
71
|
+
- **Automatic JSON Serialization**: No need to manually encode/decode JSON
|
|
72
|
+
- **Authentication**: Basic Auth and Bearer Token support
|
|
73
|
+
- **Comprehensive Error Handling**: Typed exceptions with standardized error codes
|
|
74
|
+
- **Timeout & Redirect Control**: Configurable timeouts and maximum redirect limits
|
|
75
|
+
- **Keep-Alive & Connection Pooling**: Reuse connections for better performance
|
|
76
|
+
- **Proxy Support**: Route requests through HTTP proxies
|
|
77
|
+
- **Unix Socket Path Support**: Connect via Unix domain sockets
|
|
78
|
+
- **Size Limits**: Configure maximum request body and response content lengths
|
|
79
|
+
- **Status Code Validation**: Custom validation functions for HTTP status codes
|
|
80
|
+
- **CSRF Protection**: Built-in support for XSRF token headers
|
|
81
|
+
- **Automatic Decompression**: Handles gzip and deflate compressed responses
|
|
82
|
+
- **Mock Adapter for Testing**: Simulate responses without network calls
|
|
83
|
+
- **Type Hints**: Full typing support for excellent IDE autocompletion
|
|
84
|
+
|
|
85
|
+
## Installation
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install atomhttp
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
With development dependencies:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install atomhttp[dev]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Quick Start
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
import asyncio
|
|
101
|
+
from atomhttp import AtomHTTP
|
|
102
|
+
|
|
103
|
+
async def main():
|
|
104
|
+
client = AtomHTTP({'baseURL': 'https://api.example.com'})
|
|
105
|
+
response = await client.get('/users')
|
|
106
|
+
print(response.status, response.data)
|
|
107
|
+
await client.close()
|
|
108
|
+
|
|
109
|
+
asyncio.run(main())
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Documentation
|
|
113
|
+
|
|
114
|
+
For complete documentation, API reference, and advanced usage examples, visit:
|
|
115
|
+
|
|
116
|
+
**[https://inject3r.github.io/atomhttp](https://inject3r.github.io/atomhttp)**
|
|
117
|
+
|
|
118
|
+
The documentation includes:
|
|
119
|
+
|
|
120
|
+
- Detailed API reference for all classes and methods
|
|
121
|
+
- Advanced usage patterns and best practices
|
|
122
|
+
- Configuration options and their effects
|
|
123
|
+
- Error handling strategies
|
|
124
|
+
- Migration guides from other HTTP clients
|
|
125
|
+
|
|
126
|
+
## Requirements
|
|
127
|
+
|
|
128
|
+
- Python 3.8+
|
|
129
|
+
- aiohttp 3.8.0+
|
|
130
|
+
|
|
131
|
+
## Running Tests
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Run all tests with coverage
|
|
135
|
+
./scripts/tests.sh
|
|
136
|
+
|
|
137
|
+
# Clean test output files
|
|
138
|
+
./scripts/test_clean.sh
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
This project is licensed under the MIT License.
|
|
144
|
+
|
|
145
|
+
## Author
|
|
146
|
+
|
|
147
|
+
**Abolfazl Hosseini**
|
|
148
|
+
|
|
149
|
+
- Email: tryuzr@gmail.com
|
|
150
|
+
- GitHub: [@inject3r](https://github.com/inject3r)
|
|
151
|
+
|
|
152
|
+
## Contributing
|
|
153
|
+
|
|
154
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
155
|
+
|
|
156
|
+
1. Fork the repository
|
|
157
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
158
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
159
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
160
|
+
5. Open a Pull Request
|
|
161
|
+
|
|
162
|
+
## Acknowledgments
|
|
163
|
+
|
|
164
|
+
- [aiohttp](https://docs.aiohttp.org/) - Async HTTP client/server framework
|
|
165
|
+
- All contributors and users of this project
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
atomhttp/__init__.py,sha256=mJTLw2s70Z8hosMQ-IfD2whldI0WLbqczamxhylo79s,2121
|
|
2
|
+
atomhttp/client.py,sha256=sHupALERyHvOCh-ZaJJJUfr8Lc2iEtbf8mLmLGP9DVo,20752
|
|
3
|
+
atomhttp/adapters/__init__.py,sha256=waRdw1NYqVo7CNzboCt0zmszXy1OTXc3j0jsGUVmRg8,117
|
|
4
|
+
atomhttp/adapters/http_adapter.py,sha256=kzYNGlXsEMl-LsfEcFnHZOglzPFnpuVTL4zFvX4Cjz0,4173
|
|
5
|
+
atomhttp/adapters/mock_adapter.py,sha256=OxeJvqIfGMqvg_4WP_rZEL_-hna-rCtKzb_T-cUmlkk,5179
|
|
6
|
+
atomhttp/auth/__init__.py,sha256=7OSniKBhYho-GvVA9gchOgf4RWwvEnT4Zi2PYkTBt7Q,108
|
|
7
|
+
atomhttp/auth/basic_auth.py,sha256=iu3qnm1Yzdf3wXe_FQ73loxQaz2ctgTUUdowOOo5-54,3350
|
|
8
|
+
atomhttp/auth/bearer_auth.py,sha256=8M9F_FeGKQz1Xi1pt0vaU1TF2Llcfq9d31iPFYs83Zc,3161
|
|
9
|
+
atomhttp/core/__init__.py,sha256=80CeSPFTVE5EtPfoiBqXFmSQamKTMoLC81VsziuNfWA,465
|
|
10
|
+
atomhttp/core/adapters.py,sha256=JxE3kTL8gXP29Kw55HQI5Qc0gxnp1uRJWiYkG4bpsRE,27054
|
|
11
|
+
atomhttp/core/config.py,sha256=15Zuov_FQWj1lDj4liOkwzrbY_-cqmIzcS7IdglPUtM,7401
|
|
12
|
+
atomhttp/core/defaults.py,sha256=G41lw8ynFE_Xd4lvd-O0-qkq8WYZHLH6LF5sZqN4bSw,7836
|
|
13
|
+
atomhttp/core/form_data.py,sha256=VLpDYAAfo4kMA46uB5btcEsAO2hrdjnACw0kTKsfyPs,10259
|
|
14
|
+
atomhttp/core/request.py,sha256=xdUozOaiHzjud8i2WFQIJNT_wWWsJQ4mBCccWQ4yPYA,10062
|
|
15
|
+
atomhttp/core/response.py,sha256=6K1ROg4rGjxTm1LAfoGGJB6yR4J3ce4iiHjkxhsZ1Rk,3372
|
|
16
|
+
atomhttp/errors/__init__.py,sha256=BUEU5qQcvlMeS7_ZUikZaj7829N_95H8LZygsFsg66k,246
|
|
17
|
+
atomhttp/errors/http_errors.py,sha256=jpCAfVD3cfMNgbk6SGdaRsruoBA0zV-u7Xndlwdqw4Y,4775
|
|
18
|
+
atomhttp/interceptors/__init__.py,sha256=djVVrsMK-mTWUTPzajBybwrHkjRQwe8ZvMOTNDdauzo,224
|
|
19
|
+
atomhttp/interceptors/manager.py,sha256=I2uidox4MjEZOq76IqM2I5APW1IjjqVMUW9uoabY_wA,5466
|
|
20
|
+
atomhttp/interceptors/request_interceptor.py,sha256=K8T0VbC37Z5DwTa6e_SiklGaqQZXKJxrxIvIAAFUOYA,721
|
|
21
|
+
atomhttp/interceptors/response_interceptor.py,sha256=so92WxoBflIwhUv8nXP_EAHMxFI2Al1C6gmv-TLTXjA,718
|
|
22
|
+
atomhttp/progress/__init__.py,sha256=pD_ea5iV-yabnro2It0iHQ3JSM17Pf6ChUiU74wNrXQ,75
|
|
23
|
+
atomhttp/progress/upload_progress.py,sha256=bVu39oCZKcaoAIx2Qip4zYTf5FTRuvNcen28MfeI8zw,3465
|
|
24
|
+
atomhttp/transforms/__init__.py,sha256=rO3nPoftABf3bUolztfRSluNJKtBv6-JzrprXKbIv_0,220
|
|
25
|
+
atomhttp/transforms/data_serializer.py,sha256=GGT1VV-pGa2vTQliHhhjHaoq_l2eR-tECdz9QtJn8ec,3245
|
|
26
|
+
atomhttp/transforms/request_transform.py,sha256=Sh9mqaz29xBMvyezA9ERwJ1yMXwQ4kRQzJRXiXxe70g,4147
|
|
27
|
+
atomhttp/transforms/response_transform.py,sha256=EBUVHdDaL505CvyyyNEh7hzEznWEOMpzjP4q45HJavk,2826
|
|
28
|
+
atomhttp/utils/__init__.py,sha256=tHngX0GRgmo3peV9eBaxwd3PltGgEemIHde7Fmcn7eo,226
|
|
29
|
+
atomhttp/utils/cookies.py,sha256=4ore5vu48BpR6m4oijEqwvywIjWJIDcqKei5KkfzEp8,4610
|
|
30
|
+
atomhttp/utils/helpers.py,sha256=RJSDuVUlKjeP9UTrfkesNbpXlkeGsp9ktym_odjbs2c,3958
|
|
31
|
+
atomhttp/utils/redirect.py,sha256=yRvQfm4aHTBODbREaHeHMEzvfAINgvCp1saAdbgBP3I,3835
|
|
32
|
+
atomhttp-1.0.0.dist-info/licenses/LICENSE,sha256=aCMFMZNf1JWWTFSFgxhyAMhACSjlaC_Q9vYbFMP_JH8,1073
|
|
33
|
+
atomhttp-1.0.0.dist-info/METADATA,sha256=i_sGyftTTqapcNq4g7UJd1OBQANLbAX95q9nigZxUwc,5911
|
|
34
|
+
atomhttp-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
35
|
+
atomhttp-1.0.0.dist-info/top_level.txt,sha256=Wx-x5YQAk-KfplY7qqB_kU9T2_JxXv49zVEdu7ZSQCo,9
|
|
36
|
+
atomhttp-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Abolfazl Hosseini
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
atomhttp
|