Skip to content
This repository was archived by the owner on Oct 28, 2023. It is now read-only.

Commit ded5c5e

Browse files
committed
Merge remote-tracking branch 'upstream/master' into basvs-merge-upstream
2 parents ebda1fd + 387a8d2 commit ded5c5e

File tree

15 files changed

+228
-61
lines changed

15 files changed

+228
-61
lines changed

docs/library/ubinascii.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,12 @@ Functions
2929

3030
.. function:: a2b_base64(data)
3131

32-
Convert Base64-encoded data to binary representation. Returns bytes string.
32+
Decode base64-encoded data, ignoring invalid characters in the input.
33+
Conforms to `RFC 2045 s.6.8 <https://tools.ietf.org/html/rfc2045#section-6.8>`_.
34+
Returns a bytes object.
3335

3436
.. function:: b2a_base64(data)
3537

36-
Encode binary data in Base64 format. Returns string.
38+
Encode binary data in base64 format, as in `RFC 3548
39+
<https://tools.ietf.org/html/rfc3548.html>`_. Returns the encoded data
40+
followed by a newline character, as a bytes object.

docs/library/usocket.rst

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@
99

1010
This module provides access to the BSD socket interface.
1111

12-
.. admonition:: Difference to CPython
13-
:class: attention
14-
15-
CPython used to have a ``socket.error`` exception which is now deprecated,
16-
and is an alias of `OSError`. In MicroPython, use `OSError` directly.
17-
1812
.. admonition:: Difference to CPython
1913
:class: attention
2014

@@ -27,11 +21,47 @@ This module provides access to the BSD socket interface.
2721
Socket address format(s)
2822
------------------------
2923

30-
The functions below which expect a network address, accept it in the format of
31-
*(ipv4_address, port)*, where *ipv4_address* is a string with dot-notation numeric
32-
IPv4 address, e.g. ``"8.8.8.8"``, and port is integer port number in the range
33-
1-65535. Note the domain names are not accepted as *ipv4_address*, they should be
34-
resolved first using `usocket.getaddrinfo()`.
24+
The native socket address format of the ``usocket`` module is an opaque data type
25+
returned by `getaddrinfo` function, which must be used to resolve textual address
26+
(including numeric addresses)::
27+
28+
sockaddr = usocket.getaddrinfo('www.micropython.org', 80)[0][-1]
29+
# You must use getaddrinfo() even for numeric addresses
30+
sockaddr = usocket.getaddrinfo('127.0.0.1', 80)[0][-1]
31+
# Now you can use that address
32+
sock.connect(addr)
33+
34+
Using `getaddrinfo` is the most efficient (both in terms of memory and processing
35+
power) and portable way to work with addresses.
36+
37+
However, ``socket`` module (note the difference with native MicroPython
38+
``usocket`` module described here) provides CPython-compatible way to specify
39+
addresses using tuples, as described below. Note that depending on a
40+
`MicroPython port`, ``socket`` module can be builtin or need to be
41+
installed from `micropython-lib` (as in the case of `MicroPython Unix port`),
42+
and some ports still accept only numeric addresses in the tuple format,
43+
and require to use `getaddrinfo` function to resolve domain names.
44+
45+
Summing up:
46+
47+
* Always use `getaddrinfo` when writing portable applications.
48+
* Tuple addresses described below can be used as a shortcut for
49+
quick hacks and interactive use, if your port supports them.
50+
51+
Tuple address format for ``socket`` module:
52+
53+
* IPv4: *(ipv4_address, port)*, where *ipv4_address* is a string with
54+
dot-notation numeric IPv4 address, e.g. ``"8.8.8.8"``, and *port* is and
55+
integer port number in the range 1-65535. Note the domain names are not
56+
accepted as *ipv4_address*, they should be resolved first using
57+
`usocket.getaddrinfo()`.
58+
* IPv6: *(ipv6_address, port, flowinfo, scopeid)*, where *ipv6_address*
59+
is a string with colon-notation numeric IPv6 address, e.g. ``"2001:db8::1"``,
60+
and *port* is an integer port number in the range 1-65535. *flowinfo*
61+
must be 0. *scopeid* is the interface scope identifier for link-local
62+
addresses. Note the domain names are not accepted as *ipv6_address*,
63+
they should be resolved first using `usocket.getaddrinfo()`. Availability
64+
of IPv6 support depends on a `MicroPython port`.
3565

3666
Functions
3767
---------
@@ -250,3 +280,13 @@ Methods
250280
the length of *buf*.
251281

252282
Return value: number of bytes written.
283+
284+
.. exception:: socket.error
285+
286+
MicroPython does NOT have this exception.
287+
288+
.. admonition:: Difference to CPython
289+
:class: attention
290+
291+
CPython used to have a ``socket.error`` exception which is now deprecated,
292+
and is an alias of `OSError`. In MicroPython, use `OSError` directly.

docs/reference/glossary.rst

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ Glossary
5454
separate project
5555
`micropython-lib <https://github.com/micropython/micropython-lib>`_
5656
which provides implementations for many modules from CPython's
57-
standard library. However, large subset of these modules required
57+
standard library. However, large subset of these modules require
5858
POSIX-like environment (Linux, MacOS, Windows may be partially
5959
supported), and thus would work or make sense only with MicroPython
60-
Unix port. Some subset of modules however usable for baremetal ports
60+
Unix port. Some subset of modules is however usable for baremetal ports
6161
too.
6262

6363
Unlike monolithic :term:`CPython` stdlib, micropython-lib modules
@@ -68,7 +68,13 @@ Glossary
6868
MicroPython supports different :term:`boards <board>`, RTOSes,
6969
and OSes, and can be relatively easily adapted to new systems.
7070
MicroPython with support for a particular system is called a
71-
"port" to that system.
71+
"port" to that system. Different ports may have widely different
72+
functionality. This documentation is intended to be a reference
73+
of the generic APIs available across different ports ("MicroPython
74+
core"). Note that some ports may still omit some APIs described
75+
here (e.g. due to resource constraints). Any such differences,
76+
and port-specific extensions beyond MicroPython core functionality,
77+
would be described in the separate port-specific documentation.
7278

7379
MicroPython Unix port
7480
Unix port is one of the major :term:`MicroPython ports <MicroPython port>`.

extmod/modubinascii.c

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -105,54 +105,64 @@ mp_obj_t mod_binascii_unhexlify(mp_obj_t data) {
105105
}
106106
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj, mod_binascii_unhexlify);
107107

108+
// If ch is a character in the base64 alphabet, and is not a pad character, then
109+
// the corresponding integer between 0 and 63, inclusively, is returned.
110+
// Otherwise, -1 is returned.
111+
static int mod_binascii_sextet(byte ch) {
112+
if (ch >= 'A' && ch <= 'Z') {
113+
return ch - 'A';
114+
} else if (ch >= 'a' && ch <= 'z') {
115+
return ch - 'a' + 26;
116+
} else if (ch >= '0' && ch <= '9') {
117+
return ch - '0' + 52;
118+
} else if (ch == '+') {
119+
return 62;
120+
} else if (ch == '/') {
121+
return 63;
122+
} else {
123+
return -1;
124+
}
125+
}
126+
108127
mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
109128
mp_buffer_info_t bufinfo;
110129
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
111-
if (bufinfo.len % 4 != 0) {
112-
mp_raise_ValueError("incorrect padding");
113-
}
130+
byte *in = bufinfo.buf;
114131

115132
vstr_t vstr;
116-
byte *in = bufinfo.buf;
117-
if (bufinfo.len == 0) {
118-
vstr_init_len(&vstr, 0);
119-
}
120-
else {
121-
vstr_init_len(&vstr, ((bufinfo.len / 4) * 3) - ((in[bufinfo.len-1] == '=') ? ((in[bufinfo.len-2] == '=') ? 2 : 1 ) : 0));
122-
}
123-
byte *out = (byte*)vstr.buf;
124-
for (mp_uint_t i = bufinfo.len; i; i -= 4) {
125-
char hold[4];
126-
for (int j = 4; j--;) {
127-
if (in[j] >= 'A' && in[j] <= 'Z') {
128-
hold[j] = in[j] - 'A';
129-
} else if (in[j] >= 'a' && in[j] <= 'z') {
130-
hold[j] = in[j] - 'a' + 26;
131-
} else if (in[j] >= '0' && in[j] <= '9') {
132-
hold[j] = in[j] - '0' + 52;
133-
} else if (in[j] == '+') {
134-
hold[j] = 62;
135-
} else if (in[j] == '/') {
136-
hold[j] = 63;
137-
} else if (in[j] == '=') {
138-
if (j < 2 || i > 4) {
139-
mp_raise_ValueError("incorrect padding");
140-
}
141-
hold[j] = 64;
142-
} else {
143-
mp_raise_ValueError("invalid character");
133+
vstr_init(&vstr, (bufinfo.len / 4) * 3 + 1); // Potentially over-allocate
134+
byte *out = (byte *)vstr.buf;
135+
136+
uint shift = 0;
137+
int nbits = 0; // Number of meaningful bits in shift
138+
bool hadpad = false; // Had a pad character since last valid character
139+
for (size_t i = 0; i < bufinfo.len; i++) {
140+
if (in[i] == '=') {
141+
if ((nbits == 2) || ((nbits == 4) && hadpad)) {
142+
nbits = 0;
143+
break;
144144
}
145+
hadpad = true;
145146
}
146-
in += 4;
147147

148-
*out++ = (hold[0]) << 2 | (hold[1]) >> 4;
149-
if (hold[2] != 64) {
150-
*out++ = (hold[1] & 0x0F) << 4 | hold[2] >> 2;
151-
if (hold[3] != 64) {
152-
*out++ = (hold[2] & 0x03) << 6 | hold[3];
153-
}
148+
int sextet = mod_binascii_sextet(in[i]);
149+
if (sextet == -1) {
150+
continue;
151+
}
152+
hadpad = false;
153+
shift = (shift << 6) | sextet;
154+
nbits += 6;
155+
156+
if (nbits >= 8) {
157+
nbits -= 8;
158+
out[vstr.len++] = (shift >> nbits) & 0xFF;
154159
}
155160
}
161+
162+
if (nbits) {
163+
mp_raise_ValueError("incorrect padding");
164+
}
165+
156166
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
157167
}
158168
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64);

extmod/modussl_mbedtls.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "py/nlr.h"
3939
#include "py/runtime.h"
4040
#include "py/stream.h"
41+
#include "py/obj.h"
4142

4243
// mbedtls_time_t
4344
#include "mbedtls/platform.h"
@@ -268,6 +269,16 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
268269
return o;
269270
}
270271

272+
STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) {
273+
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
274+
if (!mp_obj_is_true(binary_form)) {
275+
mp_raise_NotImplementedError(NULL);
276+
}
277+
const mbedtls_x509_crt* peer_cert = mbedtls_ssl_get_peer_cert(&o->ssl);
278+
return mp_obj_new_bytes(peer_cert->raw.p, peer_cert->raw.len);
279+
}
280+
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert);
281+
271282
STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
272283
(void)kind;
273284
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
@@ -345,6 +356,7 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
345356
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
346357
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
347358
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
359+
{ MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) },
348360
};
349361

350362
STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);

py/binary.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@
2929
#include "py/obj.h"
3030

3131
// Use special typecode to differentiate repr() of bytearray vs array.array('B')
32-
// (underlyingly they're same).
33-
#define BYTEARRAY_TYPECODE 0
32+
// (underlyingly they're same). Can't use 0 here because that's used to detect
33+
// type-specification errors due to end-of-string.
34+
#define BYTEARRAY_TYPECODE 1
3435

3536
size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign);
3637
mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index);

tests/basics/struct2.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,30 @@
4040
struct.calcsize('0z')
4141
except:
4242
print('Exception')
43+
44+
# check that a count without a type specifier raises an exception
45+
46+
try:
47+
struct.calcsize('1')
48+
except:
49+
print('Exception')
50+
51+
try:
52+
struct.pack('1')
53+
except:
54+
print('Exception')
55+
56+
try:
57+
struct.pack_into('1', bytearray(4), 0, 'xx')
58+
except:
59+
print('Exception')
60+
61+
try:
62+
struct.unpack('1', 'xx')
63+
except:
64+
print('Exception')
65+
66+
try:
67+
struct.unpack_from('1', 'xx')
68+
except:
69+
print('Exception')

tests/extmod/ubinascii_a2b_base64.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@
2121
print(binascii.a2b_base64(b'f4D+')) # convert '+'
2222
print(binascii.a2b_base64(b'MTIzNEFCQ0RhYmNk'))
2323

24+
# Ignore invalid characters and pad sequences
25+
print(binascii.a2b_base64(b'Zm9v\n'))
26+
print(binascii.a2b_base64(b'Zm\x009v\n'))
27+
print(binascii.a2b_base64(b'Zm9v=='))
28+
print(binascii.a2b_base64(b'Zm9v==='))
29+
print(binascii.a2b_base64(b'Zm9v===YmFy'))
30+
2431
try:
2532
print(binascii.a2b_base64(b'abc'))
2633
except ValueError:

tests/net_hosted/ssl_getpeercert.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# test ssl.getpeercert() method
2+
3+
try:
4+
import usocket as socket
5+
import ussl as ssl
6+
except:
7+
import socket
8+
import ssl
9+
10+
11+
def test(peer_addr):
12+
s = socket.socket()
13+
s.connect(peer_addr)
14+
s = ssl.wrap_socket(s)
15+
cert = s.getpeercert(True)
16+
print(type(cert), len(cert) > 100)
17+
s.close()
18+
19+
20+
if __name__ == "__main__":
21+
test(socket.getaddrinfo('micropython.org', 443)[0][-1])
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<class 'bytes'> True

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy