diff options
-rw-r--r-- | Doc/howto/regex.rst | 2 | ||||
-rw-r--r-- | Lib/httplib.py | 15 | ||||
-rw-r--r-- | Lib/test/string_tests.py | 8 | ||||
-rw-r--r-- | Lib/test/test_format.py | 20 | ||||
-rw-r--r-- | Lib/test/test_httplib.py | 36 | ||||
-rw-r--r-- | Misc/cheatsheet | 4 | ||||
-rw-r--r-- | Modules/_ctypes/_ctypes_test.c | 2 | ||||
-rw-r--r-- | Objects/unicodeobject.c | 44 |
8 files changed, 110 insertions, 21 deletions
diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst index 406ce1c..40f5fdb 100644 --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -203,7 +203,7 @@ this RE against the string ``abcbd``. | | | ``bc``. | +------+-----------+---------------------------------+ | 6 | ``abcb`` | Try ``b`` again. This time | -| | | but the character at the | +| | | the character at the | | | | current position is ``'b'``, so | | | | it succeeds. | +------+-----------+---------------------------------+ diff --git a/Lib/httplib.py b/Lib/httplib.py index 638a92b..de27c17 100644 --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -448,7 +448,12 @@ class HTTPResponse: try: self.length = int(length) except ValueError: - pass + self.length = None + else: + if self.length < 0: # ignore nonsensical negative lengths + self.length = None + else: + self.length = None # does the body have a fixed length? (of zero) if (status == NO_CONTENT or status == NOT_MODIFIED or @@ -569,7 +574,13 @@ class HTTPResponse: i = line.find(b";") if i >= 0: line = line[:i] # strip chunk-extensions - chunk_left = int(line, 16) + try: + chunk_left = int(line, 16) + except ValueError: + # close the connection as protocol synchronisation is + # probably lost + self.close() + raise IncompleteRead(value) if chunk_left == 0: break if amt is None: diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index 24fca59..caafb31 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1053,7 +1053,13 @@ class MixinStrUnicodeUserStringTest: # unicode raises ValueError, str raises OverflowError self.checkraises((ValueError, OverflowError), '%c', '__mod__', ordinal) + longvalue = sys.maxsize + 10 + slongvalue = str(longvalue) + if slongvalue[-1] in ("L","l"): slongvalue = slongvalue[:-1] self.checkequal(' 42', '%3ld', '__mod__', 42) + self.checkequal('42', '%d', '__mod__', 42.0) + self.checkequal(slongvalue, '%d', '__mod__', longvalue) + self.checkcall('%d', '__mod__', float(longvalue)) self.checkequal('0042.00', '%07.2f', '__mod__', 42) self.checkequal('0042.00', '%07.2F', '__mod__', 42) @@ -1063,6 +1069,8 @@ class MixinStrUnicodeUserStringTest: self.checkraises(TypeError, '%c', '__mod__', (None,)) self.checkraises(ValueError, '%(foo', '__mod__', {}) self.checkraises(TypeError, '%(foo)s %(bar)s', '__mod__', ('foo', 42)) + self.checkraises(TypeError, '%d', '__mod__', "42") # not numeric + self.checkraises(TypeError, '%d', '__mod__', (42+0j)) # no int/long conversion provided # argument names with properly nested brackets are supported self.checkequal('bar', '%((foo))s', '__mod__', {'(foo)': 'bar'}) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index 9f4528c..7070286 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -11,7 +11,7 @@ maxsize = MAX_Py_ssize_t overflowok = 1 overflowrequired = 0 -def testformat(formatstr, args, output=None): +def testformat(formatstr, args, output=None, limit=None): if verbose: if output: print("%r %% %r =? %r ..." %\ @@ -30,11 +30,22 @@ def testformat(formatstr, args, output=None): if verbose: print('no') print("overflow expected on %r %% %r" % (formatstr, args)) - elif output and result != output: + elif output and limit is None and result != output: if verbose: print('no') print("%r %% %r == %r != %r" %\ (formatstr, args, result, output)) + # when 'limit' is specified, it determines how many characters + # must match exactly; lengths must always match. + # ex: limit=5, '12345678' matches '12345___' + # (mainly for floating point format tests for which an exact match + # can't be guaranteed due to rounding and representation errors) + elif output and limit is not None and ( + len(result)!=len(output) or result[:limit]!=output[:limit]): + if verbose: + print('no') + print("%s %% %s == %s != %s" % \ + (repr(formatstr), repr(args), repr(result), repr(output))) else: if verbose: print('yes') @@ -91,6 +102,7 @@ testformat("%.2d", big, "123456789012345678901234567890") testformat("%.30d", big, "123456789012345678901234567890") testformat("%.31d", big, "0123456789012345678901234567890") testformat("%32.31d", big, " 0123456789012345678901234567890") +testformat("%d", float(big), "123456________________________", 6) big = 0x1234567890abcdef12345 # 21 hex digits testformat("%x", big, "1234567890abcdef12345") @@ -128,6 +140,7 @@ testformat("%#+27.23X", big, " +0X001234567890ABCDEF12345") testformat("%#+027.23X", big, "+0X0001234567890ABCDEF12345") # same, except no 0 flag testformat("%#+27.23X", big, " +0X001234567890ABCDEF12345") +testformat("%x", float(big), "123456_______________", 6) big = 0o12345670123456701234567012345670 # 32 octal digits testformat("%o", big, "12345670123456701234567012345670") @@ -169,6 +182,7 @@ testformat("%034.33o", big, "0012345670123456701234567012345670") testformat("%0#38.33o", big, "0o000012345670123456701234567012345670") # padding spaces come before marker testformat("%#36.33o", big, " 0o012345670123456701234567012345670") +testformat("%o", float(big), "123456__________________________", 6) # Some small ints, in both Python int and long flavors). testformat("%d", 42, "42") @@ -186,11 +200,13 @@ testformat("%#X", 0, "0X0") testformat("%x", 0x42, "42") testformat("%x", -0x42, "-42") +testformat("%x", float(0x42), "42") testformat("%o", 0o42, "42") testformat("%o", -0o42, "-42") testformat("%o", 0o42, "42") testformat("%o", -0o42, "-42") +testformat("%o", float(0o42), "42") # Test exception for unknown format characters if verbose: diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 4caf996..ca801da 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -159,6 +159,42 @@ class BasicTest(TestCase): self.assertTrue(sock.data.startswith(expected), '%r != %r' % (sock.data[:len(expected)], expected)) + def test_chunked(self): + chunked_start = ( + 'HTTP/1.1 200 OK\r\n' + 'Transfer-Encoding: chunked\r\n\r\n' + 'a\r\n' + 'hello worl\r\n' + '1\r\n' + 'd\r\n' + ) + sock = FakeSocket(chunked_start + '0\r\n') + resp = httplib.HTTPResponse(sock, method="GET") + resp.begin() + self.assertEquals(resp.read(), b'hello world') + resp.close() + + for x in ('', 'foo\r\n'): + sock = FakeSocket(chunked_start + x) + resp = httplib.HTTPResponse(sock, method="GET") + resp.begin() + try: + resp.read() + except httplib.IncompleteRead as i: + self.assertEquals(i.partial, b'hello world') + else: + self.fail('IncompleteRead expected') + finally: + resp.close() + + def test_negative_content_length(self): + sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: -1\r\n\r\nHello\r\n') + resp = httplib.HTTPResponse(sock, method="GET") + resp.begin() + self.assertEquals(resp.read(), b'Hello\r\n') + resp.close() + + class OfflineTest(TestCase): def test_responses(self): self.assertEquals(httplib.responses[httplib.NOT_FOUND], "Not Found") diff --git a/Misc/cheatsheet b/Misc/cheatsheet index c530442..cc56036 100644 --- a/Misc/cheatsheet +++ b/Misc/cheatsheet @@ -561,8 +561,8 @@ d Signed integer decimal. i Signed integer decimal. o Unsigned octal. u Unsigned decimal. -x Unsigned hexidecimal (lowercase). -X Unsigned hexidecimal (uppercase). +x Unsigned hexadecimal (lowercase). +X Unsigned hexadecimal (uppercase). e Floating point exponential format (lowercase). E Floating point exponential format (uppercase). f Floating point decimal format. diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index 7048a2e..63fb580 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -398,7 +398,7 @@ EXPORT(int) unpack_bitfields(struct BITS *bits, char name) return 0; } -PyMethodDef module_methods[] = { +static PyMethodDef module_methods[] = { /* {"get_last_tf_arg_s", get_last_tf_arg_s, METH_NOARGS}, {"get_last_tf_arg_u", get_last_tf_arg_u, METH_NOARGS}, */ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 86d8b54..7359821 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -8600,6 +8600,7 @@ PyObject *PyUnicode_Format(PyObject *format, int prec = -1; Py_UNICODE c = '\0'; Py_UNICODE fill; + int isnumok; PyObject *v = NULL; PyObject *temp = NULL; Py_UNICODE *pbuf; @@ -8804,21 +8805,38 @@ PyObject *PyUnicode_Format(PyObject *format, case 'X': if (c == 'i') c = 'd'; - if (PyLong_Check(v)) { - temp = formatlong(v, flags, prec, c); - if (!temp) - goto onError; - pbuf = PyUnicode_AS_UNICODE(temp); - len = PyUnicode_GET_SIZE(temp); - sign = 1; + isnumok = 0; + if (PyNumber_Check(v)) { + PyObject *iobj=NULL; + + if (PyLong_Check(v)) { + iobj = v; + Py_INCREF(iobj); + } + else { + iobj = PyNumber_Long(v); + } + if (iobj!=NULL) { + if (PyLong_Check(iobj)) { + isnumok = 1; + temp = formatlong(iobj, flags, prec, c); + Py_DECREF(iobj); + if (!temp) + goto onError; + pbuf = PyUnicode_AS_UNICODE(temp); + len = PyUnicode_GET_SIZE(temp); + sign = 1; + } + else { + Py_DECREF(iobj); + } + } } - else { - pbuf = formatbuf; - len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), - flags, prec, c, v); - if (len < 0) + if (!isnumok) { + PyErr_Format(PyExc_TypeError, + "%%%c format: a number is required, " + "not %.200s", c, Py_TYPE(v)->tp_name); goto onError; - sign = 1; } if (flags & F_ZERO) fill = '0'; |