uhttp-server 2.3.2__tar.gz → 2.3.4__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.
Files changed (44) hide show
  1. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/PKG-INFO +15 -8
  2. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/README.md +14 -7
  3. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_keepalive_simple.py +4 -4
  4. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/uhttp/server.py +5 -1
  5. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/uhttp_server.egg-info/PKG-INFO +15 -8
  6. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/.github/workflows/micropython.yml +0 -0
  7. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/.github/workflows/publish.yml +0 -0
  8. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/.github/workflows/tests.yml +0 -0
  9. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/.gitignore +0 -0
  10. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/LICENSE +0 -0
  11. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/examples/client_with_server.py +0 -0
  12. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/examples/http_to_https_redirect.py +0 -0
  13. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/examples/https_server.py +0 -0
  14. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/pyproject.toml +0 -0
  15. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/setup.cfg +0 -0
  16. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/__init__.py +0 -0
  17. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_100_continue.py +0 -0
  18. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_concurrent_connections.py +0 -0
  19. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_content_length_security.py +0 -0
  20. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_data_parsing.py +0 -0
  21. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_double_response.py +0 -0
  22. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_eagain.py +0 -0
  23. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_error_handling.py +0 -0
  24. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_event_mode.py +0 -0
  25. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_ipv6.py +0 -0
  26. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_keepalive.py +0 -0
  27. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_keepalive_basic.py +0 -0
  28. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_keepalive_http10.py +0 -0
  29. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_keepalive_limits.py +0 -0
  30. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_mpy_integration.py +0 -0
  31. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_mpy_websocket.py +0 -0
  32. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_multipart.py +0 -0
  33. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_pipelining.py +0 -0
  34. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_respond_falsy.py +0 -0
  35. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_respond_file.py +0 -0
  36. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_respond_file_race.py +0 -0
  37. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_ssl.py +0 -0
  38. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_timeout_during_response.py +0 -0
  39. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_utils.py +0 -0
  40. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_websocket.py +0 -0
  41. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/tests/test_websocket_utils.py +0 -0
  42. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/uhttp_server.egg-info/SOURCES.txt +0 -0
  43. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/uhttp_server.egg-info/dependency_links.txt +0 -0
  44. {uhttp_server-2.3.2 → uhttp_server-2.3.4}/uhttp_server.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uhttp-server
3
- Version: 2.3.2
3
+ Version: 2.3.4
4
4
  Summary: Micro HTTP server for Python and MicroPython
5
5
  Author-email: Pavel Revak <pavelrevak@gmail.com>
6
6
  License: MIT
@@ -480,6 +480,8 @@ Parameters:
480
480
 
481
481
  uHTTP supports WebSocket connections (RFC 6455) in both event mode and non-event mode.
482
482
 
483
+ **Important:** When using `process_events()` with external select loop, `event_mode=True` is required for WebSocket support.
484
+
483
485
  ### Event Mode (non-blocking, multiple connections)
484
486
 
485
487
  ```python
@@ -504,17 +506,20 @@ while True:
504
506
  client.respond({'status': 'ok'})
505
507
 
506
508
  elif client.event == EVENT_WS_MESSAGE:
507
- # str for text frames, bytes for binary frames
508
- client.ws_send(client.ws_message) # echo
509
+ data = client.read_buffer() # bytes
510
+ if client.ws_is_text:
511
+ client.ws_send(data.decode('utf-8')) # echo as text
512
+ else:
513
+ client.ws_send(data) # echo as binary
509
514
 
510
515
  elif client.event == EVENT_WS_CHUNK_FIRST:
511
- client.context = {'chunks': [client.ws_message]}
516
+ client.context = {'chunks': [client.read_buffer()]}
512
517
 
513
518
  elif client.event == EVENT_WS_CHUNK_NEXT:
514
- client.context['chunks'].append(client.ws_message)
519
+ client.context['chunks'].append(client.read_buffer())
515
520
 
516
521
  elif client.event == EVENT_WS_CHUNK_LAST:
517
- client.context['chunks'].append(client.ws_message)
522
+ client.context['chunks'].append(client.read_buffer())
518
523
  # process all chunks...
519
524
  client.ws_send('received')
520
525
 
@@ -549,10 +554,12 @@ while True:
549
554
  **HttpConnection properties:**
550
555
  - `is_websocket_request` - True if request is a WebSocket upgrade
551
556
  - `is_websocket` - True if connection is in WebSocket mode
552
- - `ws_message` - Last received message (str for text, bytes for binary)
557
+ - `ws_is_text` - True if current message is text frame (vs binary)
558
+ - `ws_message` - Ping/close payload (only for `EVENT_WS_PING` and `EVENT_WS_CLOSE`)
553
559
 
554
560
  **HttpConnection methods (event mode):**
555
561
  - `accept_websocket()` - Accept upgrade, switch to WebSocket mode
562
+ - `read_buffer()` - Read message data (returns bytes, use `ws_is_text` to check type)
556
563
  - `ws_send(data)` - Send message (str → text frame, bytes → binary frame)
557
564
  - `ws_ping(data=b'')` - Send ping frame
558
565
  - `ws_close(code=1000, reason='')` - Close WebSocket connection
@@ -566,7 +573,7 @@ while True:
566
573
 
567
574
  ### Large Message Chunking
568
575
 
569
- Messages larger than `MAX_WS_MESSAGE_LENGTH` (default 64KB, configurable via `max_ws_message_length` kwarg) are delivered in chunks via `EVENT_WS_CHUNK_FIRST`, `EVENT_WS_CHUNK_NEXT`, `EVENT_WS_CHUNK_LAST` events. All chunk events contain data in `ws_message`.
576
+ Messages larger than `MAX_WS_MESSAGE_LENGTH` (default 64KB, configurable via `max_ws_message_length` kwarg) are delivered in chunks via `EVENT_WS_CHUNK_FIRST`, `EVENT_WS_CHUNK_NEXT`, `EVENT_WS_CHUNK_LAST` events. Read chunk data with `read_buffer()`, check frame type with `ws_is_text`.
570
577
 
571
578
  In non-event mode, messages exceeding the limit close the connection with status 1009.
572
579
 
@@ -463,6 +463,8 @@ Parameters:
463
463
 
464
464
  uHTTP supports WebSocket connections (RFC 6455) in both event mode and non-event mode.
465
465
 
466
+ **Important:** When using `process_events()` with external select loop, `event_mode=True` is required for WebSocket support.
467
+
466
468
  ### Event Mode (non-blocking, multiple connections)
467
469
 
468
470
  ```python
@@ -487,17 +489,20 @@ while True:
487
489
  client.respond({'status': 'ok'})
488
490
 
489
491
  elif client.event == EVENT_WS_MESSAGE:
490
- # str for text frames, bytes for binary frames
491
- client.ws_send(client.ws_message) # echo
492
+ data = client.read_buffer() # bytes
493
+ if client.ws_is_text:
494
+ client.ws_send(data.decode('utf-8')) # echo as text
495
+ else:
496
+ client.ws_send(data) # echo as binary
492
497
 
493
498
  elif client.event == EVENT_WS_CHUNK_FIRST:
494
- client.context = {'chunks': [client.ws_message]}
499
+ client.context = {'chunks': [client.read_buffer()]}
495
500
 
496
501
  elif client.event == EVENT_WS_CHUNK_NEXT:
497
- client.context['chunks'].append(client.ws_message)
502
+ client.context['chunks'].append(client.read_buffer())
498
503
 
499
504
  elif client.event == EVENT_WS_CHUNK_LAST:
500
- client.context['chunks'].append(client.ws_message)
505
+ client.context['chunks'].append(client.read_buffer())
501
506
  # process all chunks...
502
507
  client.ws_send('received')
503
508
 
@@ -532,10 +537,12 @@ while True:
532
537
  **HttpConnection properties:**
533
538
  - `is_websocket_request` - True if request is a WebSocket upgrade
534
539
  - `is_websocket` - True if connection is in WebSocket mode
535
- - `ws_message` - Last received message (str for text, bytes for binary)
540
+ - `ws_is_text` - True if current message is text frame (vs binary)
541
+ - `ws_message` - Ping/close payload (only for `EVENT_WS_PING` and `EVENT_WS_CLOSE`)
536
542
 
537
543
  **HttpConnection methods (event mode):**
538
544
  - `accept_websocket()` - Accept upgrade, switch to WebSocket mode
545
+ - `read_buffer()` - Read message data (returns bytes, use `ws_is_text` to check type)
539
546
  - `ws_send(data)` - Send message (str → text frame, bytes → binary frame)
540
547
  - `ws_ping(data=b'')` - Send ping frame
541
548
  - `ws_close(code=1000, reason='')` - Close WebSocket connection
@@ -549,7 +556,7 @@ while True:
549
556
 
550
557
  ### Large Message Chunking
551
558
 
552
- Messages larger than `MAX_WS_MESSAGE_LENGTH` (default 64KB, configurable via `max_ws_message_length` kwarg) are delivered in chunks via `EVENT_WS_CHUNK_FIRST`, `EVENT_WS_CHUNK_NEXT`, `EVENT_WS_CHUNK_LAST` events. All chunk events contain data in `ws_message`.
559
+ Messages larger than `MAX_WS_MESSAGE_LENGTH` (default 64KB, configurable via `max_ws_message_length` kwarg) are delivered in chunks via `EVENT_WS_CHUNK_FIRST`, `EVENT_WS_CHUNK_NEXT`, `EVENT_WS_CHUNK_LAST` events. Read chunk data with `read_buffer()`, check frame type with `ws_is_text`.
553
560
 
554
561
  In non-event mode, messages exceeding the limit close the connection with status 1009.
555
562
 
@@ -58,7 +58,7 @@ class TestKeepAliveSimple(unittest.TestCase):
58
58
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
59
59
  try:
60
60
  sock.connect(('localhost', self.PORT))
61
- sock.settimeout(0.5)
61
+ sock.settimeout(2.0)
62
62
 
63
63
  responses = []
64
64
 
@@ -119,7 +119,7 @@ class TestKeepAliveSimple(unittest.TestCase):
119
119
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
120
120
  try:
121
121
  sock.connect(('localhost', self.PORT))
122
- sock.settimeout(0.5)
122
+ sock.settimeout(2.0)
123
123
 
124
124
  request = b"GET /test HTTP/1.1\r\nHost: localhost\r\n\r\n"
125
125
  sock.send(request)
@@ -167,7 +167,7 @@ class TestKeepAliveSimple(unittest.TestCase):
167
167
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
168
168
  try:
169
169
  sock.connect(('localhost', self.PORT))
170
- sock.settimeout(0.5)
170
+ sock.settimeout(2.0)
171
171
 
172
172
  request = b"GET /test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"
173
173
  sock.send(request)
@@ -197,7 +197,7 @@ class TestKeepAliveSimple(unittest.TestCase):
197
197
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
198
198
  try:
199
199
  sock.connect(('localhost', self.PORT))
200
- sock.settimeout(0.5)
200
+ sock.settimeout(2.0)
201
201
 
202
202
  request_numbers = []
203
203
 
@@ -128,6 +128,7 @@ STATUS_CODES = {
128
128
  405: "Method Not Allowed",
129
129
  406: "Not Acceptable",
130
130
  408: "Request Timeout",
131
+ 409: "Conflict",
131
132
  410: "Gone",
132
133
  411: "Length Required",
133
134
  413: "Payload Too Large",
@@ -781,7 +782,10 @@ class HttpConnection(_WsFrameMixin):
781
782
 
782
783
  @property
783
784
  def data(self):
784
- """Content data"""
785
+ """Content data (parsed JSON/form or raw bytes)"""
786
+ # Lazy parse buffer on EVENT_COMPLETE (after accept_body)
787
+ if self._data is None and self._event == EVENT_COMPLETE and self._buffer:
788
+ self._process_data()
785
789
  return self._data
786
790
 
787
791
  @property
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uhttp-server
3
- Version: 2.3.2
3
+ Version: 2.3.4
4
4
  Summary: Micro HTTP server for Python and MicroPython
5
5
  Author-email: Pavel Revak <pavelrevak@gmail.com>
6
6
  License: MIT
@@ -480,6 +480,8 @@ Parameters:
480
480
 
481
481
  uHTTP supports WebSocket connections (RFC 6455) in both event mode and non-event mode.
482
482
 
483
+ **Important:** When using `process_events()` with external select loop, `event_mode=True` is required for WebSocket support.
484
+
483
485
  ### Event Mode (non-blocking, multiple connections)
484
486
 
485
487
  ```python
@@ -504,17 +506,20 @@ while True:
504
506
  client.respond({'status': 'ok'})
505
507
 
506
508
  elif client.event == EVENT_WS_MESSAGE:
507
- # str for text frames, bytes for binary frames
508
- client.ws_send(client.ws_message) # echo
509
+ data = client.read_buffer() # bytes
510
+ if client.ws_is_text:
511
+ client.ws_send(data.decode('utf-8')) # echo as text
512
+ else:
513
+ client.ws_send(data) # echo as binary
509
514
 
510
515
  elif client.event == EVENT_WS_CHUNK_FIRST:
511
- client.context = {'chunks': [client.ws_message]}
516
+ client.context = {'chunks': [client.read_buffer()]}
512
517
 
513
518
  elif client.event == EVENT_WS_CHUNK_NEXT:
514
- client.context['chunks'].append(client.ws_message)
519
+ client.context['chunks'].append(client.read_buffer())
515
520
 
516
521
  elif client.event == EVENT_WS_CHUNK_LAST:
517
- client.context['chunks'].append(client.ws_message)
522
+ client.context['chunks'].append(client.read_buffer())
518
523
  # process all chunks...
519
524
  client.ws_send('received')
520
525
 
@@ -549,10 +554,12 @@ while True:
549
554
  **HttpConnection properties:**
550
555
  - `is_websocket_request` - True if request is a WebSocket upgrade
551
556
  - `is_websocket` - True if connection is in WebSocket mode
552
- - `ws_message` - Last received message (str for text, bytes for binary)
557
+ - `ws_is_text` - True if current message is text frame (vs binary)
558
+ - `ws_message` - Ping/close payload (only for `EVENT_WS_PING` and `EVENT_WS_CLOSE`)
553
559
 
554
560
  **HttpConnection methods (event mode):**
555
561
  - `accept_websocket()` - Accept upgrade, switch to WebSocket mode
562
+ - `read_buffer()` - Read message data (returns bytes, use `ws_is_text` to check type)
556
563
  - `ws_send(data)` - Send message (str → text frame, bytes → binary frame)
557
564
  - `ws_ping(data=b'')` - Send ping frame
558
565
  - `ws_close(code=1000, reason='')` - Close WebSocket connection
@@ -566,7 +573,7 @@ while True:
566
573
 
567
574
  ### Large Message Chunking
568
575
 
569
- Messages larger than `MAX_WS_MESSAGE_LENGTH` (default 64KB, configurable via `max_ws_message_length` kwarg) are delivered in chunks via `EVENT_WS_CHUNK_FIRST`, `EVENT_WS_CHUNK_NEXT`, `EVENT_WS_CHUNK_LAST` events. All chunk events contain data in `ws_message`.
576
+ Messages larger than `MAX_WS_MESSAGE_LENGTH` (default 64KB, configurable via `max_ws_message_length` kwarg) are delivered in chunks via `EVENT_WS_CHUNK_FIRST`, `EVENT_WS_CHUNK_NEXT`, `EVENT_WS_CHUNK_LAST` events. Read chunk data with `read_buffer()`, check frame type with `ws_is_text`.
570
577
 
571
578
  In non-event mode, messages exceeding the limit close the connection with status 1009.
572
579
 
File without changes
File without changes
File without changes