Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
e007860b
Kaydet (Commit)
e007860b
authored
Haz 28, 2009
tarafından
Kristján Valur Jónsson
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
http://bugs.python.org/issue6267
Cumulative patch to http and xmlrpc
üst
552e7a7e
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
408 additions
and
72 deletions
+408
-72
simplexmlrpcserver.rst
Doc/library/simplexmlrpcserver.rst
+9
-0
BaseHTTPServer.py
Lib/BaseHTTPServer.py
+18
-10
DocXMLRPCServer.py
Lib/DocXMLRPCServer.py
+0
-4
SimpleXMLRPCServer.py
Lib/SimpleXMLRPCServer.py
+51
-6
SocketServer.py
Lib/SocketServer.py
+8
-3
test_xmlrpc.py
Lib/test/test_xmlrpc.py
+128
-14
xmlrpclib.py
Lib/xmlrpclib.py
+194
-35
No files found.
Doc/library/simplexmlrpcserver.rst
Dosyayı görüntüle @
e007860b
...
@@ -133,6 +133,15 @@ alone XML-RPC servers.
...
@@ -133,6 +133,15 @@ alone XML-RPC servers.
.. versionadded:: 2.5
.. versionadded:: 2.5
.. attribute:: SimpleXMLRPCRequestHandler.encode_threshold
If this attribute is not ``None``, responses larger than this value
will be encoded using the *gzip* transfer encoding, if permitted by
the client. The default is ``1400`` which corresponds roughly
to a single TCP packet.
.. versionadded:: 2.7
.. _simplexmlrpcserver-example:
.. _simplexmlrpcserver-example:
SimpleXMLRPCServer Example
SimpleXMLRPCServer Example
...
...
Lib/BaseHTTPServer.py
Dosyayı görüntüle @
e007860b
...
@@ -309,18 +309,26 @@ class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
...
@@ -309,18 +309,26 @@ class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
commands such as GET and POST.
commands such as GET and POST.
"""
"""
self
.
raw_requestline
=
self
.
rfile
.
readline
()
try
:
if
not
self
.
raw_requestline
:
self
.
raw_requestline
=
self
.
rfile
.
readline
()
if
not
self
.
raw_requestline
:
self
.
close_connection
=
1
return
if
not
self
.
parse_request
():
# An error code has been sent, just exit
return
mname
=
'do_'
+
self
.
command
if
not
hasattr
(
self
,
mname
):
self
.
send_error
(
501
,
"Unsupported method (
%
r)"
%
self
.
command
)
return
method
=
getattr
(
self
,
mname
)
method
()
self
.
wfile
.
flush
()
#actually send the response if not already done.
except
socket
.
timeout
,
e
:
#a read or a write timed out. Discard this connection
self
.
log_error
(
"Request timed out:
%
r"
,
e
)
self
.
close_connection
=
1
self
.
close_connection
=
1
return
return
if
not
self
.
parse_request
():
# An error code has been sent, just exit
return
mname
=
'do_'
+
self
.
command
if
not
hasattr
(
self
,
mname
):
self
.
send_error
(
501
,
"Unsupported method (
%
r)"
%
self
.
command
)
return
method
=
getattr
(
self
,
mname
)
method
()
def
handle
(
self
):
def
handle
(
self
):
"""Handle multiple requests if necessary."""
"""Handle multiple requests if necessary."""
...
...
Lib/DocXMLRPCServer.py
Dosyayı görüntüle @
e007860b
...
@@ -240,10 +240,6 @@ class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
...
@@ -240,10 +240,6 @@ class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
self
.
end_headers
()
self
.
end_headers
()
self
.
wfile
.
write
(
response
)
self
.
wfile
.
write
(
response
)
# shut down the connection
self
.
wfile
.
flush
()
self
.
connection
.
shutdown
(
1
)
class
DocXMLRPCServer
(
SimpleXMLRPCServer
,
class
DocXMLRPCServer
(
SimpleXMLRPCServer
,
XMLRPCDocGenerator
):
XMLRPCDocGenerator
):
"""XML-RPC and HTML documentation server.
"""XML-RPC and HTML documentation server.
...
...
Lib/SimpleXMLRPCServer.py
Dosyayı görüntüle @
e007860b
...
@@ -106,6 +106,7 @@ import BaseHTTPServer
...
@@ -106,6 +106,7 @@ import BaseHTTPServer
import
sys
import
sys
import
os
import
os
import
traceback
import
traceback
import
re
try
:
try
:
import
fcntl
import
fcntl
except
ImportError
:
except
ImportError
:
...
@@ -430,6 +431,31 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
...
@@ -430,6 +431,31 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
# paths not on this list will result in a 404 error.
# paths not on this list will result in a 404 error.
rpc_paths
=
(
'/'
,
'/RPC2'
)
rpc_paths
=
(
'/'
,
'/RPC2'
)
#if not None, encode responses larger than this, if possible
encode_threshold
=
1400
#a common MTU
#Override form StreamRequestHandler: full buffering of output
#and no Nagle.
wbufsize
=
-
1
disable_nagle_algorithm
=
True
# a re to match a gzip Accept-Encoding
aepattern
=
re
.
compile
(
r"""
\s* ([^\s;]+) \s* #content-coding
(;\s* q \s*=\s* ([0-9\.]+))? #q
"""
,
re
.
VERBOSE
|
re
.
IGNORECASE
)
def
accept_encodings
(
self
):
r
=
{}
ae
=
self
.
headers
.
get
(
"Accept-Encoding"
,
""
)
for
e
in
ae
.
split
(
","
):
match
=
self
.
aepattern
.
match
(
e
)
if
match
:
v
=
match
.
group
(
3
)
v
=
float
(
v
)
if
v
else
1.0
r
[
match
.
group
(
1
)]
=
v
return
r
def
is_rpc_path_valid
(
self
):
def
is_rpc_path_valid
(
self
):
if
self
.
rpc_paths
:
if
self
.
rpc_paths
:
return
self
.
path
in
self
.
rpc_paths
return
self
.
path
in
self
.
rpc_paths
...
@@ -463,6 +489,10 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
...
@@ -463,6 +489,10 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
size_remaining
-=
len
(
L
[
-
1
])
size_remaining
-=
len
(
L
[
-
1
])
data
=
''
.
join
(
L
)
data
=
''
.
join
(
L
)
data
=
self
.
decode_request_content
(
data
)
if
data
is
None
:
return
#response has been sent
# In previous versions of SimpleXMLRPCServer, _dispatch
# In previous versions of SimpleXMLRPCServer, _dispatch
# could be overridden in this class, instead of in
# could be overridden in this class, instead of in
# SimpleXMLRPCDispatcher. To maintain backwards compatibility,
# SimpleXMLRPCDispatcher. To maintain backwards compatibility,
...
@@ -481,18 +511,36 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
...
@@ -481,18 +511,36 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
self
.
send_header
(
"X-exception"
,
str
(
e
))
self
.
send_header
(
"X-exception"
,
str
(
e
))
self
.
send_header
(
"X-traceback"
,
traceback
.
format_exc
())
self
.
send_header
(
"X-traceback"
,
traceback
.
format_exc
())
self
.
send_header
(
"Content-length"
,
"0"
)
self
.
end_headers
()
self
.
end_headers
()
else
:
else
:
# got a valid XML RPC response
# got a valid XML RPC response
self
.
send_response
(
200
)
self
.
send_response
(
200
)
self
.
send_header
(
"Content-type"
,
"text/xml"
)
self
.
send_header
(
"Content-type"
,
"text/xml"
)
if
self
.
encode_threshold
is
not
None
:
if
len
(
response
)
>
self
.
encode_threshold
:
q
=
self
.
accept_encodings
()
.
get
(
"gzip"
,
0
)
if
q
:
response
=
xmlrpclib
.
gzip_encode
(
response
)
self
.
send_header
(
"Content-Encoding"
,
"gzip"
)
self
.
send_header
(
"Content-length"
,
str
(
len
(
response
)))
self
.
send_header
(
"Content-length"
,
str
(
len
(
response
)))
self
.
end_headers
()
self
.
end_headers
()
self
.
wfile
.
write
(
response
)
self
.
wfile
.
write
(
response
)
# shut down the connection
def
decode_request_content
(
self
,
data
):
self
.
wfile
.
flush
()
#support gzip encoding of request
self
.
connection
.
shutdown
(
1
)
encoding
=
self
.
headers
.
get
(
"content-encoding"
,
"identity"
)
.
lower
()
if
encoding
==
"identity"
:
return
data
if
encoding
==
"gzip"
:
try
:
return
xmlrpclib
.
gzip_decode
(
data
)
except
ValueError
:
self
.
send_response
(
400
,
"error decoding gzip content"
)
else
:
self
.
send_response
(
501
,
"encoding
%
r not supported"
%
encoding
)
self
.
send_header
(
"Content-length"
,
"0"
)
self
.
end_headers
()
def
report_404
(
self
):
def
report_404
(
self
):
# Report a 404 error
# Report a 404 error
...
@@ -502,9 +550,6 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
...
@@ -502,9 +550,6 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
self
.
send_header
(
"Content-length"
,
str
(
len
(
response
)))
self
.
send_header
(
"Content-length"
,
str
(
len
(
response
)))
self
.
end_headers
()
self
.
end_headers
()
self
.
wfile
.
write
(
response
)
self
.
wfile
.
write
(
response
)
# shut down the connection
self
.
wfile
.
flush
()
self
.
connection
.
shutdown
(
1
)
def
log_request
(
self
,
code
=
'-'
,
size
=
'-'
):
def
log_request
(
self
,
code
=
'-'
,
size
=
'-'
):
"""Selectively log an accepted request."""
"""Selectively log an accepted request."""
...
...
Lib/SocketServer.py
Dosyayı görüntüle @
e007860b
...
@@ -445,6 +445,7 @@ class TCPServer(BaseServer):
...
@@ -445,6 +445,7 @@ class TCPServer(BaseServer):
def
close_request
(
self
,
request
):
def
close_request
(
self
,
request
):
"""Called to clean up an individual request."""
"""Called to clean up an individual request."""
request
.
shutdown
(
socket
.
SHUT_WR
)
request
.
close
()
request
.
close
()
...
@@ -610,12 +611,11 @@ class BaseRequestHandler:
...
@@ -610,12 +611,11 @@ class BaseRequestHandler:
self
.
request
=
request
self
.
request
=
request
self
.
client_address
=
client_address
self
.
client_address
=
client_address
self
.
server
=
server
self
.
server
=
server
self
.
setup
()
try
:
try
:
self
.
setup
()
self
.
handle
()
self
.
handle
()
self
.
finish
()
finally
:
finally
:
s
ys
.
exc_traceback
=
None
# Help garbage collection
s
elf
.
finish
()
def
setup
(
self
):
def
setup
(
self
):
pass
pass
...
@@ -649,12 +649,17 @@ class StreamRequestHandler(BaseRequestHandler):
...
@@ -649,12 +649,17 @@ class StreamRequestHandler(BaseRequestHandler):
rbufsize
=
-
1
rbufsize
=
-
1
wbufsize
=
0
wbufsize
=
0
# A timeout to apply to the request socket, if not None.
timeout
=
None
# Disable nagle algoritm for this socket, if True.
# Disable nagle algoritm for this socket, if True.
# Use only when wbufsize != 0, to avoid small packets.
# Use only when wbufsize != 0, to avoid small packets.
disable_nagle_algorithm
=
False
disable_nagle_algorithm
=
False
def
setup
(
self
):
def
setup
(
self
):
self
.
connection
=
self
.
request
self
.
connection
=
self
.
request
if
self
.
timeout
is
not
None
:
self
.
connection
.
settimeout
(
self
.
timeout
)
if
self
.
disable_nagle_algorithm
:
if
self
.
disable_nagle_algorithm
:
self
.
connection
.
setsockopt
(
socket
.
IPPROTO_TCP
,
self
.
connection
.
setsockopt
(
socket
.
IPPROTO_TCP
,
socket
.
TCP_NODELAY
,
True
)
socket
.
TCP_NODELAY
,
True
)
...
...
Lib/test/test_xmlrpc.py
Dosyayı görüntüle @
e007860b
...
@@ -273,7 +273,7 @@ ADDR = PORT = URL = None
...
@@ -273,7 +273,7 @@ ADDR = PORT = URL = None
# The evt is set twice. First when the server is ready to serve.
# The evt is set twice. First when the server is ready to serve.
# Second when the server has been shutdown. The user must clear
# Second when the server has been shutdown. The user must clear
# the event after it has been set the first time to catch the second set.
# the event after it has been set the first time to catch the second set.
def
http_server
(
evt
,
numrequests
):
def
http_server
(
evt
,
numrequests
,
requestHandler
=
None
):
class
TestInstanceClass
:
class
TestInstanceClass
:
def
div
(
self
,
x
,
y
):
def
div
(
self
,
x
,
y
):
return
x
//
y
return
x
//
y
...
@@ -294,7 +294,9 @@ def http_server(evt, numrequests):
...
@@ -294,7 +294,9 @@ def http_server(evt, numrequests):
s
.
setblocking
(
True
)
s
.
setblocking
(
True
)
return
s
,
port
return
s
,
port
serv
=
MyXMLRPCServer
((
"localhost"
,
0
),
if
not
requestHandler
:
requestHandler
=
SimpleXMLRPCServer
.
SimpleXMLRPCRequestHandler
serv
=
MyXMLRPCServer
((
"localhost"
,
0
),
requestHandler
,
logRequests
=
False
,
bind_and_activate
=
False
)
logRequests
=
False
,
bind_and_activate
=
False
)
try
:
try
:
serv
.
socket
.
settimeout
(
3
)
serv
.
socket
.
settimeout
(
3
)
...
@@ -348,34 +350,36 @@ def is_unavailable_exception(e):
...
@@ -348,34 +350,36 @@ def is_unavailable_exception(e):
return
False
return
False
# NOTE: The tests in SimpleServerTestCase will ignore failures caused by
class
BaseServerTestCase
(
unittest
.
TestCase
):
# "temporarily unavailable" exceptions raised in SimpleXMLRPCServer. This
requestHandler
=
None
# condition occurs infrequently on some platforms, frequently on others, and
# is apparently caused by using SimpleXMLRPCServer with a non-blocking socket.
# If the server class is updated at some point in the future to handle this
# situation more gracefully, these tests should be modified appropriately.
class
SimpleServerTestCase
(
unittest
.
TestCase
):
def
setUp
(
self
):
def
setUp
(
self
):
# enable traceback reporting
# enable traceback reporting
SimpleXMLRPCServer
.
SimpleXMLRPCServer
.
_send_traceback_header
=
True
SimpleXMLRPCServer
.
SimpleXMLRPCServer
.
_send_traceback_header
=
True
self
.
evt
=
threading
.
Event
()
self
.
evt
=
threading
.
Event
()
# start server thread to handle requests
# start server thread to handle requests
serv_args
=
(
self
.
evt
,
1
)
serv_args
=
(
self
.
evt
,
1
,
self
.
requestHandler
)
threading
.
Thread
(
target
=
http_server
,
args
=
serv_args
)
.
start
()
threading
.
Thread
(
target
=
http_server
,
args
=
serv_args
)
.
start
()
# wait for the server to be ready
# wait for the server to be ready
self
.
evt
.
wait
()
self
.
evt
.
wait
(
10
)
self
.
evt
.
clear
()
self
.
evt
.
clear
()
def
tearDown
(
self
):
def
tearDown
(
self
):
# wait on the server thread to terminate
# wait on the server thread to terminate
self
.
evt
.
wait
()
self
.
evt
.
wait
(
10
)
# disable traceback reporting
# disable traceback reporting
SimpleXMLRPCServer
.
SimpleXMLRPCServer
.
_send_traceback_header
=
False
SimpleXMLRPCServer
.
SimpleXMLRPCServer
.
_send_traceback_header
=
False
# NOTE: The tests in SimpleServerTestCase will ignore failures caused by
# "temporarily unavailable" exceptions raised in SimpleXMLRPCServer. This
# condition occurs infrequently on some platforms, frequently on others, and
# is apparently caused by using SimpleXMLRPCServer with a non-blocking socket
# If the server class is updated at some point in the future to handle this
# situation more gracefully, these tests should be modified appropriately.
class
SimpleServerTestCase
(
BaseServerTestCase
):
def
test_simple1
(
self
):
def
test_simple1
(
self
):
try
:
try
:
p
=
xmlrpclib
.
ServerProxy
(
URL
)
p
=
xmlrpclib
.
ServerProxy
(
URL
)
...
@@ -512,6 +516,110 @@ class SimpleServerTestCase(unittest.TestCase):
...
@@ -512,6 +516,110 @@ class SimpleServerTestCase(unittest.TestCase):
# This avoids waiting for the socket timeout.
# This avoids waiting for the socket timeout.
self
.
test_simple1
()
self
.
test_simple1
()
#A test case that verifies that a server using the HTTP/1.1 keep-alive mechanism
#does indeed serve subsequent requests on the same connection
class
KeepaliveServerTestCase
(
BaseServerTestCase
):
#a request handler that supports keep-alive and logs requests into a
#class variable
class
RequestHandler
(
SimpleXMLRPCServer
.
SimpleXMLRPCRequestHandler
):
parentClass
=
SimpleXMLRPCServer
.
SimpleXMLRPCRequestHandler
protocol_version
=
'HTTP/1.1'
myRequests
=
[]
def
handle
(
self
):
self
.
myRequests
.
append
([])
return
self
.
parentClass
.
handle
(
self
)
def
handle_one_request
(
self
):
result
=
self
.
parentClass
.
handle_one_request
(
self
)
self
.
myRequests
[
-
1
]
.
append
(
self
.
raw_requestline
)
return
result
requestHandler
=
RequestHandler
def
setUp
(
self
):
#clear request log
self
.
RequestHandler
.
myRequests
=
[]
return
BaseServerTestCase
.
setUp
(
self
)
def
test_two
(
self
):
p
=
xmlrpclib
.
ServerProxy
(
URL
)
self
.
assertEqual
(
p
.
pow
(
6
,
8
),
6
**
8
)
self
.
assertEqual
(
p
.
pow
(
6
,
8
),
6
**
8
)
self
.
assertEqual
(
len
(
self
.
RequestHandler
.
myRequests
),
1
)
#we may or may not catch the final "append" with the empty line
self
.
assertTrue
(
len
(
self
.
RequestHandler
.
myRequests
[
-
1
])
>=
2
)
#A test case that verifies that gzip encoding works in both directions
#(for a request and the response)
class
GzipServerTestCase
(
BaseServerTestCase
):
#a request handler that supports keep-alive and logs requests into a
#class variable
class
RequestHandler
(
SimpleXMLRPCServer
.
SimpleXMLRPCRequestHandler
):
parentClass
=
SimpleXMLRPCServer
.
SimpleXMLRPCRequestHandler
protocol_version
=
'HTTP/1.1'
def
do_POST
(
self
):
#store content of last request in class
self
.
__class__
.
content_length
=
int
(
self
.
headers
[
"content-length"
])
return
self
.
parentClass
.
do_POST
(
self
)
requestHandler
=
RequestHandler
class
Transport
(
xmlrpclib
.
Transport
):
#custom transport, stores the response length for our perusal
fake_gzip
=
False
def
parse_response
(
self
,
response
):
self
.
response_length
=
int
(
response
.
getheader
(
"content-length"
,
0
))
return
xmlrpclib
.
Transport
.
parse_response
(
self
,
response
)
def
send_content
(
self
,
connection
,
body
):
if
self
.
fake_gzip
:
#add a lone gzip header to induce decode error remotely
connection
.
putheader
(
"Content-Encoding"
,
"gzip"
)
return
xmlrpclib
.
Transport
.
send_content
(
self
,
connection
,
body
)
def
test_gzip_request
(
self
):
t
=
self
.
Transport
()
t
.
encode_threshold
=
None
p
=
xmlrpclib
.
ServerProxy
(
URL
,
transport
=
t
)
self
.
assertEqual
(
p
.
pow
(
6
,
8
),
6
**
8
)
a
=
self
.
RequestHandler
.
content_length
t
.
encode_threshold
=
0
#turn on request encoding
self
.
assertEqual
(
p
.
pow
(
6
,
8
),
6
**
8
)
b
=
self
.
RequestHandler
.
content_length
self
.
assertTrue
(
a
>
b
)
def
test_bad_gzip_request
(
self
):
t
=
self
.
Transport
()
t
.
encode_threshold
=
None
t
.
fake_gzip
=
True
p
=
xmlrpclib
.
ServerProxy
(
URL
,
transport
=
t
)
cm
=
self
.
assertRaisesRegexp
(
xmlrpclib
.
ProtocolError
,
re
.
compile
(
r"\b400\b"
))
with
cm
:
p
.
pow
(
6
,
8
)
def
test_gsip_response
(
self
):
t
=
self
.
Transport
()
p
=
xmlrpclib
.
ServerProxy
(
URL
,
transport
=
t
)
old
=
self
.
requestHandler
.
encode_threshold
self
.
requestHandler
.
encode_threshold
=
None
#no encoding
self
.
assertEqual
(
p
.
pow
(
6
,
8
),
6
**
8
)
a
=
t
.
response_length
self
.
requestHandler
.
encode_threshold
=
0
#always encode
self
.
assertEqual
(
p
.
pow
(
6
,
8
),
6
**
8
)
b
=
t
.
response_length
self
.
requestHandler
.
encode_threshold
=
old
self
.
assertTrue
(
a
>
b
)
#Test special attributes of the ServerProxy object
class
ServerProxyTestCase
(
unittest
.
TestCase
):
def
test_close
(
self
):
p
=
xmlrpclib
.
ServerProxy
(
URL
)
self
.
assertEqual
(
p
(
'close'
)(),
None
)
def
test_transport
(
self
):
t
=
xmlrpclib
.
Transport
()
p
=
xmlrpclib
.
ServerProxy
(
URL
,
transport
=
t
)
self
.
assertEqual
(
p
(
'transport'
),
t
)
# This is a contrived way to make a failure occur on the server side
# This is a contrived way to make a failure occur on the server side
# in order to test the _send_traceback_header flag on the server
# in order to test the _send_traceback_header flag on the server
class
FailingMessageClass
(
mimetools
.
Message
):
class
FailingMessageClass
(
mimetools
.
Message
):
...
@@ -693,6 +801,9 @@ class FakeSocket:
...
@@ -693,6 +801,9 @@ class FakeSocket:
def
makefile
(
self
,
x
=
'r'
,
y
=-
1
):
def
makefile
(
self
,
x
=
'r'
,
y
=-
1
):
raise
RuntimeError
raise
RuntimeError
def
close
(
self
):
pass
class
FakeTransport
(
xmlrpclib
.
Transport
):
class
FakeTransport
(
xmlrpclib
.
Transport
):
"""A Transport instance that records instead of sending a request.
"""A Transport instance that records instead of sending a request.
...
@@ -703,7 +814,7 @@ class FakeTransport(xmlrpclib.Transport):
...
@@ -703,7 +814,7 @@ class FakeTransport(xmlrpclib.Transport):
def
make_connection
(
self
,
host
):
def
make_connection
(
self
,
host
):
conn
=
xmlrpclib
.
Transport
.
make_connection
(
self
,
host
)
conn
=
xmlrpclib
.
Transport
.
make_connection
(
self
,
host
)
conn
.
_conn
.
sock
=
self
.
fake_socket
=
FakeSocket
()
conn
.
sock
=
self
.
fake_socket
=
FakeSocket
()
return
conn
return
conn
class
TransportSubclassTestCase
(
unittest
.
TestCase
):
class
TransportSubclassTestCase
(
unittest
.
TestCase
):
...
@@ -763,6 +874,9 @@ def test_main():
...
@@ -763,6 +874,9 @@ def test_main():
xmlrpc_tests
=
[
XMLRPCTestCase
,
HelperTestCase
,
DateTimeTestCase
,
xmlrpc_tests
=
[
XMLRPCTestCase
,
HelperTestCase
,
DateTimeTestCase
,
BinaryTestCase
,
FaultTestCase
,
TransportSubclassTestCase
]
BinaryTestCase
,
FaultTestCase
,
TransportSubclassTestCase
]
xmlrpc_tests
.
append
(
SimpleServerTestCase
)
xmlrpc_tests
.
append
(
SimpleServerTestCase
)
xmlrpc_tests
.
append
(
KeepaliveServerTestCase
)
xmlrpc_tests
.
append
(
GzipServerTestCase
)
xmlrpc_tests
.
append
(
ServerProxyTestCase
)
xmlrpc_tests
.
append
(
FailingServerTestCase
)
xmlrpc_tests
.
append
(
FailingServerTestCase
)
xmlrpc_tests
.
append
(
CGIHandlerTestCase
)
xmlrpc_tests
.
append
(
CGIHandlerTestCase
)
...
...
Lib/xmlrpclib.py
Dosyayı görüntüle @
e007860b
...
@@ -139,6 +139,10 @@ Exported functions:
...
@@ -139,6 +139,10 @@ Exported functions:
import
re
,
string
,
time
,
operator
import
re
,
string
,
time
,
operator
from
types
import
*
from
types
import
*
import
gzip
import
socket
import
errno
import
httplib
# --------------------------------------------------------------------
# --------------------------------------------------------------------
# Internal stuff
# Internal stuff
...
@@ -1129,6 +1133,72 @@ def loads(data, use_datetime=0):
...
@@ -1129,6 +1133,72 @@ def loads(data, use_datetime=0):
p
.
close
()
p
.
close
()
return
u
.
close
(),
u
.
getmethodname
()
return
u
.
close
(),
u
.
getmethodname
()
##
# Encode a string using the gzip content encoding such as specified by the
# Content-Encoding: gzip
# in the HTTP header, as described in RFC 1952
#
# @param data the unencoded data
# @return the encoded data
def
gzip_encode
(
data
):
"""data -> gzip encoded data
Encode data using the gzip content encoding as described in RFC 1952
"""
f
=
StringIO
.
StringIO
()
gzf
=
gzip
.
GzipFile
(
mode
=
"wb"
,
fileobj
=
f
,
compresslevel
=
1
)
gzf
.
write
(
data
)
gzf
.
close
()
encoded
=
f
.
getvalue
()
f
.
close
()
return
encoded
##
# Decode a string using the gzip content encoding such as specified by the
# Content-Encoding: gzip
# in the HTTP header, as described in RFC 1952
#
# @param data The encoded data
# @return the unencoded data
# @raises ValueError if data is not correctly coded.
def
gzip_decode
(
data
):
"""gzip encoded data -> unencoded data
Decode data using the gzip content encoding as described in RFC 1952
"""
f
=
StringIO
.
StringIO
(
data
)
gzf
=
gzip
.
GzipFile
(
mode
=
"rb"
,
fileobj
=
f
)
try
:
decoded
=
gzf
.
read
()
except
IOError
:
raise
ValueError
(
"invalid data"
)
f
.
close
()
gzf
.
close
()
return
decoded
##
# Return a decoded file-like object for the gzip encoding
# as described in RFC 1952.
#
# @param response A stream supporting a read() method
# @return a file-like object that the decoded data can be read() from
class
GzipDecodedResponse
(
gzip
.
GzipFile
):
"""a file-like object to decode a response encoded with the gzip
method, as described in RFC 1952.
"""
def
__init__
(
self
,
response
):
#response doesn't support tell() and read(), required by
#GzipFile
self
.
stringio
=
StringIO
.
StringIO
(
response
.
read
())
gzip
.
GzipFile
.
__init__
(
self
,
mode
=
"rb"
,
fileobj
=
self
.
stringio
)
def
close
(
self
):
gzip
.
GzipFile
.
close
(
self
)
self
.
stringio
.
close
()
# --------------------------------------------------------------------
# --------------------------------------------------------------------
# request dispatcher
# request dispatcher
...
@@ -1156,11 +1226,21 @@ class Transport:
...
@@ -1156,11 +1226,21 @@ class Transport:
# client identifier (may be overridden)
# client identifier (may be overridden)
user_agent
=
"xmlrpclib.py/
%
s (by www.pythonware.com)"
%
__version__
user_agent
=
"xmlrpclib.py/
%
s (by www.pythonware.com)"
%
__version__
#if true, we'll request gzip encoding
accept_gzip_encoding
=
True
# if positive, encode request using gzip if it exceeds this threshold
# note that many server will get confused, so only use it if you know
# that they can decode such a request
encode_threshold
=
None
#None = don't encode
def
__init__
(
self
,
use_datetime
=
0
):
def
__init__
(
self
,
use_datetime
=
0
):
self
.
_use_datetime
=
use_datetime
self
.
_use_datetime
=
use_datetime
self
.
_connection
=
(
None
,
None
)
self
.
_extra_headers
=
[]
##
##
# Send a complete request, and parse the response.
# Send a complete request, and parse the response.
# Retry request if a cached connection has disconnected.
#
#
# @param host Target host.
# @param host Target host.
# @param handler Target PRC handler.
# @param handler Target PRC handler.
...
@@ -1169,29 +1249,59 @@ class Transport:
...
@@ -1169,29 +1249,59 @@ class Transport:
# @return Parsed response.
# @return Parsed response.
def
request
(
self
,
host
,
handler
,
request_body
,
verbose
=
0
):
def
request
(
self
,
host
,
handler
,
request_body
,
verbose
=
0
):
#retry request once if cached connection has gone cold
for
i
in
(
0
,
1
):
try
:
return
self
.
single_request
(
host
,
handler
,
request_body
,
verbose
)
except
(
socket
.
error
,
httplib
.
HTTPException
),
e
:
retry
=
(
errno
.
ECONNRESET
,
errno
.
ECONNABORTED
,
httplib
.
BadStatusLine
)
#close after we sent request
if
i
or
e
[
0
]
not
in
retry
:
raise
##
# Send a complete request, and parse the response.
#
# @param host Target host.
# @param handler Target PRC handler.
# @param request_body XML-RPC request body.
# @param verbose Debugging flag.
# @return Parsed response.
def
single_request
(
self
,
host
,
handler
,
request_body
,
verbose
=
0
):
# issue XML-RPC request
# issue XML-RPC request
h
=
self
.
make_connection
(
host
)
h
=
self
.
make_connection
(
host
)
if
verbose
:
if
verbose
:
h
.
set_debuglevel
(
1
)
h
.
set_debuglevel
(
1
)
self
.
send_request
(
h
,
handler
,
request_body
)
try
:
self
.
send_host
(
h
,
host
)
self
.
send_request
(
h
,
handler
,
request_body
)
self
.
send_user_agent
(
h
)
self
.
send_host
(
h
,
host
)
self
.
send_content
(
h
,
request_body
)
self
.
send_user_agent
(
h
)
self
.
send_content
(
h
,
request_body
)
errcode
,
errmsg
,
headers
=
h
.
getreply
(
buffering
=
True
)
response
=
h
.
getresponse
(
buffering
=
True
)
if
errcode
!=
200
:
if
response
.
status
==
200
:
raise
ProtocolError
(
self
.
verbose
=
verbose
host
+
handler
,
return
self
.
parse_response
(
response
)
errcode
,
errmsg
,
except
Fault
:
headers
raise
)
except
Exception
:
# All unexpected errors leave connection in
self
.
verbose
=
verbose
# a strange state, so we clear it.
self
.
close
()
return
self
.
parse_response
(
h
.
getfile
())
raise
#discard any response data and raise exception
if
(
response
.
getheader
(
"content-length"
,
0
)):
response
.
read
()
raise
ProtocolError
(
host
+
handler
,
response
.
status
,
response
.
reason
,
response
.
msg
,
)
##
##
# Create parser.
# Create parser.
...
@@ -1240,10 +1350,25 @@ class Transport:
...
@@ -1240,10 +1350,25 @@ class Transport:
# @return A connection handle.
# @return A connection handle.
def
make_connection
(
self
,
host
):
def
make_connection
(
self
,
host
):
#return an existing connection if possible. This allows
#HTTP/1.1 keep-alive.
if
self
.
_connection
and
host
==
self
.
_connection
[
0
]:
return
self
.
_connection
[
1
]
# create a HTTP connection object from a host descriptor
# create a HTTP connection object from a host descriptor
import
httplib
chost
,
self
.
_extra_headers
,
x509
=
self
.
get_host_info
(
host
)
host
,
extra_headers
,
x509
=
self
.
get_host_info
(
host
)
#store the host argument along with the connection object
return
httplib
.
HTTP
(
host
)
self
.
_connection
=
host
,
httplib
.
HTTPConnection
(
chost
)
return
self
.
_connection
[
1
]
##
# Clear any cached connection object.
# Used in the event of socket errors.
#
def
close
(
self
):
if
self
.
_connection
[
1
]:
self
.
_connection
[
1
]
.
close
()
self
.
_connection
=
(
None
,
None
)
##
##
# Send request header.
# Send request header.
...
@@ -1253,17 +1378,24 @@ class Transport:
...
@@ -1253,17 +1378,24 @@ class Transport:
# @param request_body XML-RPC body.
# @param request_body XML-RPC body.
def
send_request
(
self
,
connection
,
handler
,
request_body
):
def
send_request
(
self
,
connection
,
handler
,
request_body
):
connection
.
putrequest
(
"POST"
,
handler
)
if
(
self
.
accept_gzip_encoding
):
connection
.
putrequest
(
"POST"
,
handler
,
skip_accept_encoding
=
True
)
connection
.
putheader
(
"Accept-Encoding"
,
"gzip"
)
else
:
connection
.
putrequest
(
"POST"
,
handler
)
##
##
# Send host name.
# Send host name.
#
#
# @param connection Connection handle.
# @param connection Connection handle.
# @param host Host name.
# @param host Host name.
#
# Note: This function doesn't actually add the "Host"
# header anymore, it is done as part of the connection.putrequest() in
# send_request() above.
def
send_host
(
self
,
connection
,
host
):
def
send_host
(
self
,
connection
,
host
):
host
,
extra_headers
,
x509
=
self
.
get_host_info
(
host
)
extra_headers
=
self
.
_extra_headers
connection
.
putheader
(
"Host"
,
host
)
if
extra_headers
:
if
extra_headers
:
if
isinstance
(
extra_headers
,
DictType
):
if
isinstance
(
extra_headers
,
DictType
):
extra_headers
=
extra_headers
.
items
()
extra_headers
=
extra_headers
.
items
()
...
@@ -1286,6 +1418,13 @@ class Transport:
...
@@ -1286,6 +1418,13 @@ class Transport:
def
send_content
(
self
,
connection
,
request_body
):
def
send_content
(
self
,
connection
,
request_body
):
connection
.
putheader
(
"Content-Type"
,
"text/xml"
)
connection
.
putheader
(
"Content-Type"
,
"text/xml"
)
#optionally encode the request
if
(
self
.
encode_threshold
is
not
None
and
self
.
encode_threshold
<
len
(
request_body
)):
connection
.
putheader
(
"Content-Encoding"
,
"gzip"
)
request_body
=
gzip_encode
(
request_body
)
connection
.
putheader
(
"Content-Length"
,
str
(
len
(
request_body
)))
connection
.
putheader
(
"Content-Length"
,
str
(
len
(
request_body
)))
connection
.
endheaders
(
request_body
)
connection
.
endheaders
(
request_body
)
...
@@ -1295,20 +1434,25 @@ class Transport:
...
@@ -1295,20 +1434,25 @@ class Transport:
# @param file Stream.
# @param file Stream.
# @return Response tuple and target method.
# @return Response tuple and target method.
def
parse_response
(
self
,
file
):
def
parse_response
(
self
,
response
):
# read response from input file/socket, and parse it
# read response data from httpresponse, and parse it
if
response
.
getheader
(
"Content-Encoding"
,
""
)
==
"gzip"
:
stream
=
GzipDecodedResponse
(
response
)
else
:
stream
=
response
p
,
u
=
self
.
getparser
()
p
,
u
=
self
.
getparser
()
while
1
:
while
1
:
response
=
file
.
read
(
1024
)
data
=
stream
.
read
(
1024
)
if
not
response
:
if
not
data
:
break
break
if
self
.
verbose
:
if
self
.
verbose
:
print
"body:"
,
repr
(
response
)
print
"body:"
,
repr
(
data
)
p
.
feed
(
response
)
p
.
feed
(
data
)
file
.
close
()
if
stream
is
not
response
:
stream
.
close
()
p
.
close
()
p
.
close
()
return
u
.
close
()
return
u
.
close
()
...
@@ -1322,18 +1466,20 @@ class SafeTransport(Transport):
...
@@ -1322,18 +1466,20 @@ class SafeTransport(Transport):
# FIXME: mostly untested
# FIXME: mostly untested
def
make_connection
(
self
,
host
):
def
make_connection
(
self
,
host
):
if
self
.
_connection
and
host
==
self
.
_connection
[
0
]:
return
self
.
_connection
[
1
]
# create a HTTPS connection object from a host descriptor
# create a HTTPS connection object from a host descriptor
# host may be a string, or a (host, x509-dict) tuple
# host may be a string, or a (host, x509-dict) tuple
import
httplib
host
,
extra_headers
,
x509
=
self
.
get_host_info
(
host
)
try
:
try
:
HTTPS
=
httplib
.
HTTPS
HTTPS
=
httplib
.
HTTPS
Connection
except
AttributeError
:
except
AttributeError
:
raise
NotImplementedError
(
raise
NotImplementedError
(
"your version of httplib doesn't support HTTPS"
"your version of httplib doesn't support HTTPS"
)
)
else
:
else
:
return
HTTPS
(
host
,
None
,
**
(
x509
or
{}))
chost
,
self
.
_extra_headers
,
x509
=
self
.
get_host_info
(
host
)
self
.
_connection
=
host
,
HTTPSConnection
(
chost
,
None
,
**
(
x509
or
{}))
return
self
.
_connection
[
1
]
##
##
# Standard server proxy. This class establishes a virtual connection
# Standard server proxy. This class establishes a virtual connection
...
@@ -1398,6 +1544,9 @@ class ServerProxy:
...
@@ -1398,6 +1544,9 @@ class ServerProxy:
self
.
__verbose
=
verbose
self
.
__verbose
=
verbose
self
.
__allow_none
=
allow_none
self
.
__allow_none
=
allow_none
def
__close
(
self
):
self
.
__transport
.
close
()
def
__request
(
self
,
methodname
,
params
):
def
__request
(
self
,
methodname
,
params
):
# call a method on the remote server
# call a method on the remote server
...
@@ -1431,6 +1580,16 @@ class ServerProxy:
...
@@ -1431,6 +1580,16 @@ class ServerProxy:
# note: to call a remote object with an non-standard name, use
# note: to call a remote object with an non-standard name, use
# result getattr(server, "strange-python-name")(args)
# result getattr(server, "strange-python-name")(args)
def
__call__
(
self
,
attr
):
"""A workaround to get special attributes on the ServerProxy
without interfering with the magic __getattr__
"""
if
attr
==
"close"
:
return
self
.
__close
elif
attr
==
"transport"
:
return
self
.
__transport
raise
AttributeError
(
"Attribute
%
r not found"
%
(
attr
,))
# compatibility
# compatibility
Server
=
ServerProxy
Server
=
ServerProxy
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment