uploadserver 5.2.1__tar.gz → 6.0.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uploadserver
3
- Version: 5.2.1
3
+ Version: 6.0.0
4
4
  Summary: Python's http.server extended to include a file upload page
5
5
  Home-page: https://github.com/Densaugeo/uploadserver
6
6
  Author: Densaugeo
@@ -8,7 +8,7 @@ Author-email: author@example.com
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.8
11
+ Requires-Python: >=3.9
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
 
@@ -17,14 +17,14 @@ License-File: LICENSE
17
17
  Python's http.server extended to include a file upload page
18
18
 
19
19
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://mit-license.org/)
20
- [![Build Status](https://travis-ci.com/Densaugeo/uploadserver.svg?branch=master)](https://travis-ci.com/github/Densaugeo/uploadserver)
20
+ [![Build Status](https://app.travis-ci.com/Densaugeo/uploadserver.svg?branch=master)](https://app.travis-ci.com/github/Densaugeo/uploadserver)
21
21
 
22
22
  ## Supported Platforms
23
23
 
24
24
  | Platform | Supported? | Notes |
25
25
  |-|-|-|
26
- | Python 3.8+ | Yes | Tested on 3.8 through 3.12 every release. |
27
- | Python 3.6-3.7 | No | Was supported by previous versions. |
26
+ | Python 3.9+ | Yes | Tested on 3.9 through 3.14 every release. |
27
+ | Python 3.6-3.8 | No | Was supported by previous versions. |
28
28
  | Python 3.5- | No | |
29
29
  | Linux | Yes | Tested on Fedora and Ubuntu every release. |
30
30
  | Windows | Yes | Occasional manual testing. Haven't noticed any obvious problems. |
@@ -123,6 +123,51 @@ curl -X POST https://localhost:8000/upload --insecure --cert client.pem -F files
123
123
 
124
124
  Note: This uses a self-signed server certificate which clients such as web browser and cURL will warn about. Most browsers will allow you to proceed after adding an exception, and cURL will work if given the -k/--insecure option. Using your own certificate from a certificate authority will avoid these warnings.
125
125
 
126
+ ## Available Options
127
+
128
+ ```
129
+ usage: __main__.py [-h] [--cgi] [--allow-replace] [--bind ADDRESS]
130
+ [--directory DIRECTORY] [--theme {light,auto,dark}]
131
+ [--server-certificate SERVER_CERTIFICATE]
132
+ [--client-certificate CLIENT_CERTIFICATE]
133
+ [--basic-auth BASIC_AUTH]
134
+ [--basic-auth-upload BASIC_AUTH_UPLOAD]
135
+ [port]
136
+
137
+ positional arguments:
138
+ port Specify alternate port [default: 8000]
139
+
140
+ options:
141
+ -h, --help show this help message and exit
142
+ --cgi Run as CGI Server
143
+ --allow-replace Replace existing file if uploaded file has the same
144
+ name. Auto rename by default.
145
+ --bind, -b ADDRESS Specify alternate bind address [default: all
146
+ interfaces]
147
+ --directory, -d DIRECTORY
148
+ Specify alternative directory [default:current
149
+ directory]
150
+ --theme {light,auto,dark}
151
+ Specify a light or dark theme for the upload page
152
+ [default: auto]
153
+ --server-certificate, --certificate, -c SERVER_CERTIFICATE
154
+ Specify HTTPS server certificate to use [default:
155
+ none]
156
+ --client-certificate CLIENT_CERTIFICATE
157
+ Specify HTTPS client certificate to accept for mutual
158
+ TLS [default: none]
159
+ --basic-auth BASIC_AUTH
160
+ Specify user:pass for basic authentication (downloads
161
+ and uploads)
162
+ --basic-auth-upload BASIC_AUTH_UPLOAD
163
+ Specify user:pass for basic authentication (uploads
164
+ only)
165
+ ```
166
+
167
+ ## Breaking Changes in 6.0.0
168
+
169
+ - Support for Python 3.8 dropped.
170
+
126
171
  ## Breaking Changes in 5.0.0
127
172
 
128
173
  - Support for Python 3.6-7 dropped.
@@ -3,14 +3,14 @@
3
3
  Python's http.server extended to include a file upload page
4
4
 
5
5
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://mit-license.org/)
6
- [![Build Status](https://travis-ci.com/Densaugeo/uploadserver.svg?branch=master)](https://travis-ci.com/github/Densaugeo/uploadserver)
6
+ [![Build Status](https://app.travis-ci.com/Densaugeo/uploadserver.svg?branch=master)](https://app.travis-ci.com/github/Densaugeo/uploadserver)
7
7
 
8
8
  ## Supported Platforms
9
9
 
10
10
  | Platform | Supported? | Notes |
11
11
  |-|-|-|
12
- | Python 3.8+ | Yes | Tested on 3.8 through 3.12 every release. |
13
- | Python 3.6-3.7 | No | Was supported by previous versions. |
12
+ | Python 3.9+ | Yes | Tested on 3.9 through 3.14 every release. |
13
+ | Python 3.6-3.8 | No | Was supported by previous versions. |
14
14
  | Python 3.5- | No | |
15
15
  | Linux | Yes | Tested on Fedora and Ubuntu every release. |
16
16
  | Windows | Yes | Occasional manual testing. Haven't noticed any obvious problems. |
@@ -109,6 +109,51 @@ curl -X POST https://localhost:8000/upload --insecure --cert client.pem -F files
109
109
 
110
110
  Note: This uses a self-signed server certificate which clients such as web browser and cURL will warn about. Most browsers will allow you to proceed after adding an exception, and cURL will work if given the -k/--insecure option. Using your own certificate from a certificate authority will avoid these warnings.
111
111
 
112
+ ## Available Options
113
+
114
+ ```
115
+ usage: __main__.py [-h] [--cgi] [--allow-replace] [--bind ADDRESS]
116
+ [--directory DIRECTORY] [--theme {light,auto,dark}]
117
+ [--server-certificate SERVER_CERTIFICATE]
118
+ [--client-certificate CLIENT_CERTIFICATE]
119
+ [--basic-auth BASIC_AUTH]
120
+ [--basic-auth-upload BASIC_AUTH_UPLOAD]
121
+ [port]
122
+
123
+ positional arguments:
124
+ port Specify alternate port [default: 8000]
125
+
126
+ options:
127
+ -h, --help show this help message and exit
128
+ --cgi Run as CGI Server
129
+ --allow-replace Replace existing file if uploaded file has the same
130
+ name. Auto rename by default.
131
+ --bind, -b ADDRESS Specify alternate bind address [default: all
132
+ interfaces]
133
+ --directory, -d DIRECTORY
134
+ Specify alternative directory [default:current
135
+ directory]
136
+ --theme {light,auto,dark}
137
+ Specify a light or dark theme for the upload page
138
+ [default: auto]
139
+ --server-certificate, --certificate, -c SERVER_CERTIFICATE
140
+ Specify HTTPS server certificate to use [default:
141
+ none]
142
+ --client-certificate CLIENT_CERTIFICATE
143
+ Specify HTTPS client certificate to accept for mutual
144
+ TLS [default: none]
145
+ --basic-auth BASIC_AUTH
146
+ Specify user:pass for basic authentication (downloads
147
+ and uploads)
148
+ --basic-auth-upload BASIC_AUTH_UPLOAD
149
+ Specify user:pass for basic authentication (uploads
150
+ only)
151
+ ```
152
+
153
+ ## Breaking Changes in 6.0.0
154
+
155
+ - Support for Python 3.8 dropped.
156
+
112
157
  ## Breaking Changes in 5.0.0
113
158
 
114
159
  - Support for Python 3.6-7 dropped.
@@ -5,7 +5,7 @@ with open('README.md', 'r') as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name='uploadserver',
8
- version='5.2.1',
8
+ version='6.0.0',
9
9
  author='Densaugeo',
10
10
  author_email='author@example.com',
11
11
  description='Python\'s http.server extended to include a file upload page',
@@ -18,7 +18,7 @@ setuptools.setup(
18
18
  'License :: OSI Approved :: MIT License',
19
19
  'Operating System :: OS Independent',
20
20
  ],
21
- python_requires='>=3.8',
21
+ python_requires='>=3.9',
22
22
  entry_points = {
23
23
  'console_scripts': ['uploadserver=uploadserver:main'],
24
24
  }
@@ -18,7 +18,7 @@ COLOR_SCHEME = {
18
18
  'dark': 'dark',
19
19
  }
20
20
 
21
- def get_upload_page(theme):
21
+ def get_upload_page(theme: str) -> bytes:
22
22
  return bytes('''<!DOCTYPE html>
23
23
  <html>
24
24
  <head>
@@ -74,7 +74,7 @@ document.getElementsByTagName('form')[0].addEventListener('submit', async e => {
74
74
  </script>
75
75
  </html>''', 'utf-8')
76
76
 
77
- def get_directory_head_injection(theme):
77
+ def get_directory_head_injection(theme: str) -> bytes:
78
78
  return bytes('''<!-- Injected by uploadserver -->
79
79
  <meta name="viewport" content="width=device-width" />
80
80
  <meta name="color-scheme" content="''' + COLOR_SCHEME.get(theme) + '''">
@@ -88,7 +88,7 @@ DIRECTORY_BODY_INJECTION = b'''<!-- Injected by uploadserver -->
88
88
  <!-- End injection by uploadserver -->
89
89
  '''
90
90
 
91
- def send_upload_page(handler):
91
+ def send_upload_page(handler: http.server.BaseHTTPRequestHandler):
92
92
  handler.send_response(http.HTTPStatus.OK)
93
93
  handler.send_header('Content-Type', 'text/html; charset=utf-8')
94
94
  handler.send_header('Content-Length', len(get_upload_page(args.theme)))
@@ -99,7 +99,7 @@ class PersistentFieldStorage(cgi.FieldStorage):
99
99
  # Override cgi.FieldStorage.make_file() method. Valid for Python 3.1 ~ 3.10.
100
100
  # Modified version of the original .make_file() method (base copied from
101
101
  # Python 3.10)
102
- def make_file(self):
102
+ def make_file(self) -> object:
103
103
  if self._binary_file:
104
104
  return tempfile.NamedTemporaryFile(mode = 'wb+',
105
105
  dir = args.directory, delete = False)
@@ -107,7 +107,9 @@ class PersistentFieldStorage(cgi.FieldStorage):
107
107
  return tempfile.NamedTemporaryFile("w+", dir = args.directory,
108
108
  delete = False, encoding = self.encoding, newline = '\n')
109
109
 
110
- def auto_rename(path):
110
+ # True argument/return type is str | pathlib.Path, but Python 3.9 doesn't
111
+ # support |
112
+ def auto_rename(path: pathlib.Path) -> pathlib.Path:
111
113
  if not os.path.exists(path):
112
114
  return path
113
115
  (base, ext) = os.path.splitext(path)
@@ -117,7 +119,8 @@ def auto_rename(path):
117
119
  return renamed_path
118
120
  raise FileExistsError(f'File {path} already exists.')
119
121
 
120
- def receive_upload(handler):
122
+ def receive_upload(handler: http.server.BaseHTTPRequestHandler,
123
+ ) -> tuple[http.HTTPStatus, str]:
121
124
  result = (http.HTTPStatus.INTERNAL_SERVER_ERROR, 'Server error')
122
125
  name_conflict = False
123
126
 
@@ -153,16 +156,19 @@ def receive_upload(handler):
153
156
  os.rename(source, destination)
154
157
  # class '_io.BytesIO', small file (< 1000B, in cgi.py), in-memory
155
158
  # buffer
156
- else:
159
+ else:
157
160
  with open(destination, 'wb') as f:
158
161
  f.write(field.file.read())
159
- handler.log_message(f'[Uploaded] "{filename}" --> {destination}')
162
+ handler.log_message('[Uploaded] "%s" --> %s', filename, destination)
160
163
  result = (http.HTTPStatus.NO_CONTENT, 'Some filename(s) changed '
161
164
  'due to name conflict' if name_conflict else 'Files accepted')
162
165
 
163
166
  return result
164
167
 
165
- def check_http_authentication_header(handler, auth):
168
+ # True return type is tuple[bool, str | None], but Python 3.9 doesn't support |
169
+ def check_http_authentication_header(
170
+ handler: http.server.BaseHTTPRequestHandler, auth: str,
171
+ ) -> tuple[bool, str]:
166
172
  auth_header = handler.headers.get('Authorization')
167
173
  if auth_header is None:
168
174
  return (False, 'No credentials given')
@@ -186,7 +192,8 @@ def check_http_authentication_header(handler, auth):
186
192
 
187
193
  return (True, None)
188
194
 
189
- def check_http_authentication(handler):
195
+ def check_http_authentication(handler: http.server.BaseHTTPRequestHandler
196
+ ) -> bool:
190
197
  """
191
198
  This function should be called in at the beginning of HTTP method handler.
192
199
  It validates Authorization header and sends back 401 response on failure.
@@ -219,7 +226,7 @@ def check_http_authentication(handler):
219
226
  valid, message = check_http_authentication_header(handler, args.basic_auth_upload)
220
227
 
221
228
  if not valid:
222
- handler.log_message(f'Request rejected ({message})')
229
+ handler.log_message('Request rejected (%s)', message)
223
230
  handler.send_response(http.HTTPStatus.UNAUTHORIZED, message)
224
231
  handler.send_header('WWW-Authenticate', 'Basic realm="uploadserver"')
225
232
  handler.end_headers()
@@ -251,7 +258,8 @@ class ListDirectoryInterception:
251
258
  content = content.replace(b'<ul>', DIRECTORY_BODY_INJECTION + b'<ul>')
252
259
  outputfile.write(content)
253
260
 
254
- def list_directory(self, path):
261
+ # True argument type is str | pathlib.Path, but Python 3.9 doesn't support |
262
+ def list_directory(self, path: pathlib.Path) -> object:
255
263
  setattr(self, 'flush_headers', self.flush_headers_interceptor)
256
264
  setattr(self, 'copyfile', self.copyfile_interceptor)
257
265
 
@@ -323,7 +331,7 @@ def intercept_first_print():
323
331
  builtins.print = old_print
324
332
  builtins.print = new_print
325
333
 
326
- def ssl_wrap(socket):
334
+ def ssl_wrap(socket: socket.socket) -> ssl.SSLSocket:
327
335
  context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
328
336
  server_root = pathlib.Path(args.directory).resolve()
329
337
 
@@ -339,7 +347,14 @@ def ssl_wrap(socket):
339
347
  f'root "{server_root}", exiting')
340
348
  sys.exit(3)
341
349
 
342
- context.load_cert_chain(certfile=server_certificate)
350
+ try:
351
+ context.load_cert_chain(certfile=server_certificate)
352
+ except ssl.SSLError as e:
353
+ print(f'Unable to load certificate "{server_certificate}", exiting\n\n'
354
+ f'NOTE: Certificate must be a single file in .pem format. If you '
355
+ 'have multiple certificate files, such as Let\'s Encrypt provides, '
356
+ 'you can cat them together to get one file.')
357
+ sys.exit(4)
343
358
 
344
359
  if args.client_certificate:
345
360
  # Client certificate handling
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uploadserver
3
- Version: 5.2.1
3
+ Version: 6.0.0
4
4
  Summary: Python's http.server extended to include a file upload page
5
5
  Home-page: https://github.com/Densaugeo/uploadserver
6
6
  Author: Densaugeo
@@ -8,7 +8,7 @@ Author-email: author@example.com
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.8
11
+ Requires-Python: >=3.9
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
 
@@ -17,14 +17,14 @@ License-File: LICENSE
17
17
  Python's http.server extended to include a file upload page
18
18
 
19
19
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://mit-license.org/)
20
- [![Build Status](https://travis-ci.com/Densaugeo/uploadserver.svg?branch=master)](https://travis-ci.com/github/Densaugeo/uploadserver)
20
+ [![Build Status](https://app.travis-ci.com/Densaugeo/uploadserver.svg?branch=master)](https://app.travis-ci.com/github/Densaugeo/uploadserver)
21
21
 
22
22
  ## Supported Platforms
23
23
 
24
24
  | Platform | Supported? | Notes |
25
25
  |-|-|-|
26
- | Python 3.8+ | Yes | Tested on 3.8 through 3.12 every release. |
27
- | Python 3.6-3.7 | No | Was supported by previous versions. |
26
+ | Python 3.9+ | Yes | Tested on 3.9 through 3.14 every release. |
27
+ | Python 3.6-3.8 | No | Was supported by previous versions. |
28
28
  | Python 3.5- | No | |
29
29
  | Linux | Yes | Tested on Fedora and Ubuntu every release. |
30
30
  | Windows | Yes | Occasional manual testing. Haven't noticed any obvious problems. |
@@ -123,6 +123,51 @@ curl -X POST https://localhost:8000/upload --insecure --cert client.pem -F files
123
123
 
124
124
  Note: This uses a self-signed server certificate which clients such as web browser and cURL will warn about. Most browsers will allow you to proceed after adding an exception, and cURL will work if given the -k/--insecure option. Using your own certificate from a certificate authority will avoid these warnings.
125
125
 
126
+ ## Available Options
127
+
128
+ ```
129
+ usage: __main__.py [-h] [--cgi] [--allow-replace] [--bind ADDRESS]
130
+ [--directory DIRECTORY] [--theme {light,auto,dark}]
131
+ [--server-certificate SERVER_CERTIFICATE]
132
+ [--client-certificate CLIENT_CERTIFICATE]
133
+ [--basic-auth BASIC_AUTH]
134
+ [--basic-auth-upload BASIC_AUTH_UPLOAD]
135
+ [port]
136
+
137
+ positional arguments:
138
+ port Specify alternate port [default: 8000]
139
+
140
+ options:
141
+ -h, --help show this help message and exit
142
+ --cgi Run as CGI Server
143
+ --allow-replace Replace existing file if uploaded file has the same
144
+ name. Auto rename by default.
145
+ --bind, -b ADDRESS Specify alternate bind address [default: all
146
+ interfaces]
147
+ --directory, -d DIRECTORY
148
+ Specify alternative directory [default:current
149
+ directory]
150
+ --theme {light,auto,dark}
151
+ Specify a light or dark theme for the upload page
152
+ [default: auto]
153
+ --server-certificate, --certificate, -c SERVER_CERTIFICATE
154
+ Specify HTTPS server certificate to use [default:
155
+ none]
156
+ --client-certificate CLIENT_CERTIFICATE
157
+ Specify HTTPS client certificate to accept for mutual
158
+ TLS [default: none]
159
+ --basic-auth BASIC_AUTH
160
+ Specify user:pass for basic authentication (downloads
161
+ and uploads)
162
+ --basic-auth-upload BASIC_AUTH_UPLOAD
163
+ Specify user:pass for basic authentication (uploads
164
+ only)
165
+ ```
166
+
167
+ ## Breaking Changes in 6.0.0
168
+
169
+ - Support for Python 3.8 dropped.
170
+
126
171
  ## Breaking Changes in 5.0.0
127
172
 
128
173
  - Support for Python 3.6-7 dropped.
File without changes
File without changes