ยปCore Development>Code coverage>Lib/socketserver.py

Python code coverage for Lib/socketserver.py

#countcontent
1n/a"""Generic socket server classes.
2n/a
3n/aThis module tries to capture the various aspects of defining a server:
4n/a
5n/aFor socket-based servers:
6n/a
7n/a- address family:
8n/a - AF_INET{,6}: IP (Internet Protocol) sockets (default)
9n/a - AF_UNIX: Unix domain sockets
10n/a - others, e.g. AF_DECNET are conceivable (see <socket.h>
11n/a- socket type:
12n/a - SOCK_STREAM (reliable stream, e.g. TCP)
13n/a - SOCK_DGRAM (datagrams, e.g. UDP)
14n/a
15n/aFor request-based servers (including socket-based):
16n/a
17n/a- client address verification before further looking at the request
18n/a (This is actually a hook for any processing that needs to look
19n/a at the request before anything else, e.g. logging)
20n/a- how to handle multiple requests:
21n/a - synchronous (one request is handled at a time)
22n/a - forking (each request is handled by a new process)
23n/a - threading (each request is handled by a new thread)
24n/a
25n/aThe classes in this module favor the server type that is simplest to
26n/awrite: a synchronous TCP/IP server. This is bad class design, but
27n/asave some typing. (There's also the issue that a deep class hierarchy
28n/aslows down method lookups.)
29n/a
30n/aThere are five classes in an inheritance diagram, four of which represent
31n/asynchronous servers of four types:
32n/a
33n/a +------------+
34n/a | BaseServer |
35n/a +------------+
36n/a |
37n/a v
38n/a +-----------+ +------------------+
39n/a | TCPServer |------->| UnixStreamServer |
40n/a +-----------+ +------------------+
41n/a |
42n/a v
43n/a +-----------+ +--------------------+
44n/a | UDPServer |------->| UnixDatagramServer |
45n/a +-----------+ +--------------------+
46n/a
47n/aNote that UnixDatagramServer derives from UDPServer, not from
48n/aUnixStreamServer -- the only difference between an IP and a Unix
49n/astream server is the address family, which is simply repeated in both
50n/aunix server classes.
51n/a
52n/aForking and threading versions of each type of server can be created
53n/ausing the ForkingMixIn and ThreadingMixIn mix-in classes. For
54n/ainstance, a threading UDP server class is created as follows:
55n/a
56n/a class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
57n/a
58n/aThe Mix-in class must come first, since it overrides a method defined
59n/ain UDPServer! Setting the various member variables also changes
60n/athe behavior of the underlying server mechanism.
61n/a
62n/aTo implement a service, you must derive a class from
63n/aBaseRequestHandler and redefine its handle() method. You can then run
64n/avarious versions of the service by combining one of the server classes
65n/awith your request handler class.
66n/a
67n/aThe request handler class must be different for datagram or stream
68n/aservices. This can be hidden by using the request handler
69n/asubclasses StreamRequestHandler or DatagramRequestHandler.
70n/a
71n/aOf course, you still have to use your head!
72n/a
73n/aFor instance, it makes no sense to use a forking server if the service
74n/acontains state in memory that can be modified by requests (since the
75n/amodifications in the child process would never reach the initial state
76n/akept in the parent process and passed to each child). In this case,
77n/ayou can use a threading server, but you will probably have to use
78n/alocks to avoid two requests that come in nearly simultaneous to apply
79n/aconflicting changes to the server state.
80n/a
81n/aOn the other hand, if you are building e.g. an HTTP server, where all
82n/adata is stored externally (e.g. in the file system), a synchronous
83n/aclass will essentially render the service "deaf" while one request is
84n/abeing handled -- which may be for a very long time if a client is slow
85n/ato read all the data it has requested. Here a threading or forking
86n/aserver is appropriate.
87n/a
88n/aIn some cases, it may be appropriate to process part of a request
89n/asynchronously, but to finish processing in a forked child depending on
90n/athe request data. This can be implemented by using a synchronous
91n/aserver and doing an explicit fork in the request handler class
92n/ahandle() method.
93n/a
94n/aAnother approach to handling multiple simultaneous requests in an
95n/aenvironment that supports neither threads nor fork (or where these are
96n/atoo expensive or inappropriate for the service) is to maintain an
97n/aexplicit table of partially finished requests and to use a selector to
98n/adecide which request to work on next (or whether to handle a new
99n/aincoming request). This is particularly important for stream services
100n/awhere each client can potentially be connected for a long time (if
101n/athreads or subprocesses cannot be used).
102n/a
103n/aFuture work:
104n/a- Standard classes for Sun RPC (which uses either UDP or TCP)
105n/a- Standard mix-in classes to implement various authentication
106n/a and encryption schemes
107n/a
108n/aXXX Open problems:
109n/a- What to do with out-of-band data?
110n/a
111n/aBaseServer:
112n/a- split generic "request" functionality out into BaseServer class.
113n/a Copyright (C) 2000 Luke Kenneth Casson Leighton <lkcl@samba.org>
114n/a
115n/a example: read entries from a SQL database (requires overriding
116n/a get_request() to return a table entry from the database).
117n/a entry is processed by a RequestHandlerClass.
118n/a
119n/a"""
120n/a
121n/a# Author of the BaseServer patch: Luke Kenneth Casson Leighton
122n/a
123n/a__version__ = "0.4"
124n/a
125n/a
126n/aimport socket
127n/aimport selectors
128n/aimport os
129n/aimport sys
130n/atry:
131n/a import threading
132n/aexcept ImportError:
133n/a import dummy_threading as threading
134n/afrom io import BufferedIOBase
135n/afrom time import monotonic as time
136n/a
137n/a__all__ = ["BaseServer", "TCPServer", "UDPServer",
138n/a "ThreadingUDPServer", "ThreadingTCPServer",
139n/a "BaseRequestHandler", "StreamRequestHandler",
140n/a "DatagramRequestHandler", "ThreadingMixIn"]
141n/aif hasattr(os, "fork"):
142n/a __all__.extend(["ForkingUDPServer","ForkingTCPServer", "ForkingMixIn"])
143n/aif hasattr(socket, "AF_UNIX"):
144n/a __all__.extend(["UnixStreamServer","UnixDatagramServer",
145n/a "ThreadingUnixStreamServer",
146n/a "ThreadingUnixDatagramServer"])
147n/a
148n/a# poll/select have the advantage of not requiring any extra file descriptor,
149n/a# contrarily to epoll/kqueue (also, they require a single syscall).
150n/aif hasattr(selectors, 'PollSelector'):
151n/a _ServerSelector = selectors.PollSelector
152n/aelse:
153n/a _ServerSelector = selectors.SelectSelector
154n/a
155n/a
156n/aclass BaseServer:
157n/a
158n/a """Base class for server classes.
159n/a
160n/a Methods for the caller:
161n/a
162n/a - __init__(server_address, RequestHandlerClass)
163n/a - serve_forever(poll_interval=0.5)
164n/a - shutdown()
165n/a - handle_request() # if you do not use serve_forever()
166n/a - fileno() -> int # for selector
167n/a
168n/a Methods that may be overridden:
169n/a
170n/a - server_bind()
171n/a - server_activate()
172n/a - get_request() -> request, client_address
173n/a - handle_timeout()
174n/a - verify_request(request, client_address)
175n/a - server_close()
176n/a - process_request(request, client_address)
177n/a - shutdown_request(request)
178n/a - close_request(request)
179n/a - service_actions()
180n/a - handle_error()
181n/a
182n/a Methods for derived classes:
183n/a
184n/a - finish_request(request, client_address)
185n/a
186n/a Class variables that may be overridden by derived classes or
187n/a instances:
188n/a
189n/a - timeout
190n/a - address_family
191n/a - socket_type
192n/a - allow_reuse_address
193n/a
194n/a Instance variables:
195n/a
196n/a - RequestHandlerClass
197n/a - socket
198n/a
199n/a """
200n/a
201n/a timeout = None
202n/a
203n/a def __init__(self, server_address, RequestHandlerClass):
204n/a """Constructor. May be extended, do not override."""
205n/a self.server_address = server_address
206n/a self.RequestHandlerClass = RequestHandlerClass
207n/a self.__is_shut_down = threading.Event()
208n/a self.__shutdown_request = False
209n/a
210n/a def server_activate(self):
211n/a """Called by constructor to activate the server.
212n/a
213n/a May be overridden.
214n/a
215n/a """
216n/a pass
217n/a
218n/a def serve_forever(self, poll_interval=0.5):
219n/a """Handle one request at a time until shutdown.
220n/a
221n/a Polls for shutdown every poll_interval seconds. Ignores
222n/a self.timeout. If you need to do periodic tasks, do them in
223n/a another thread.
224n/a """
225n/a self.__is_shut_down.clear()
226n/a try:
227n/a # XXX: Consider using another file descriptor or connecting to the
228n/a # socket to wake this up instead of polling. Polling reduces our
229n/a # responsiveness to a shutdown request and wastes cpu at all other
230n/a # times.
231n/a with _ServerSelector() as selector:
232n/a selector.register(self, selectors.EVENT_READ)
233n/a
234n/a while not self.__shutdown_request:
235n/a ready = selector.select(poll_interval)
236n/a if ready:
237n/a self._handle_request_noblock()
238n/a
239n/a self.service_actions()
240n/a finally:
241n/a self.__shutdown_request = False
242n/a self.__is_shut_down.set()
243n/a
244n/a def shutdown(self):
245n/a """Stops the serve_forever loop.
246n/a
247n/a Blocks until the loop has finished. This must be called while
248n/a serve_forever() is running in another thread, or it will
249n/a deadlock.
250n/a """
251n/a self.__shutdown_request = True
252n/a self.__is_shut_down.wait()
253n/a
254n/a def service_actions(self):
255n/a """Called by the serve_forever() loop.
256n/a
257n/a May be overridden by a subclass / Mixin to implement any code that
258n/a needs to be run during the loop.
259n/a """
260n/a pass
261n/a
262n/a # The distinction between handling, getting, processing and finishing a
263n/a # request is fairly arbitrary. Remember:
264n/a #
265n/a # - handle_request() is the top-level call. It calls selector.select(),
266n/a # get_request(), verify_request() and process_request()
267n/a # - get_request() is different for stream or datagram sockets
268n/a # - process_request() is the place that may fork a new process or create a
269n/a # new thread to finish the request
270n/a # - finish_request() instantiates the request handler class; this
271n/a # constructor will handle the request all by itself
272n/a
273n/a def handle_request(self):
274n/a """Handle one request, possibly blocking.
275n/a
276n/a Respects self.timeout.
277n/a """
278n/a # Support people who used socket.settimeout() to escape
279n/a # handle_request before self.timeout was available.
280n/a timeout = self.socket.gettimeout()
281n/a if timeout is None:
282n/a timeout = self.timeout
283n/a elif self.timeout is not None:
284n/a timeout = min(timeout, self.timeout)
285n/a if timeout is not None:
286n/a deadline = time() + timeout
287n/a
288n/a # Wait until a request arrives or the timeout expires - the loop is
289n/a # necessary to accommodate early wakeups due to EINTR.
290n/a with _ServerSelector() as selector:
291n/a selector.register(self, selectors.EVENT_READ)
292n/a
293n/a while True:
294n/a ready = selector.select(timeout)
295n/a if ready:
296n/a return self._handle_request_noblock()
297n/a else:
298n/a if timeout is not None:
299n/a timeout = deadline - time()
300n/a if timeout < 0:
301n/a return self.handle_timeout()
302n/a
303n/a def _handle_request_noblock(self):
304n/a """Handle one request, without blocking.
305n/a
306n/a I assume that selector.select() has returned that the socket is
307n/a readable before this function was called, so there should be no risk of
308n/a blocking in get_request().
309n/a """
310n/a try:
311n/a request, client_address = self.get_request()
312n/a except OSError:
313n/a return
314n/a if self.verify_request(request, client_address):
315n/a try:
316n/a self.process_request(request, client_address)
317n/a except Exception:
318n/a self.handle_error(request, client_address)
319n/a self.shutdown_request(request)
320n/a except:
321n/a self.shutdown_request(request)
322n/a raise
323n/a else:
324n/a self.shutdown_request(request)
325n/a
326n/a def handle_timeout(self):
327n/a """Called if no new request arrives within self.timeout.
328n/a
329n/a Overridden by ForkingMixIn.
330n/a """
331n/a pass
332n/a
333n/a def verify_request(self, request, client_address):
334n/a """Verify the request. May be overridden.
335n/a
336n/a Return True if we should proceed with this request.
337n/a
338n/a """
339n/a return True
340n/a
341n/a def process_request(self, request, client_address):
342n/a """Call finish_request.
343n/a
344n/a Overridden by ForkingMixIn and ThreadingMixIn.
345n/a
346n/a """
347n/a self.finish_request(request, client_address)
348n/a self.shutdown_request(request)
349n/a
350n/a def server_close(self):
351n/a """Called to clean-up the server.
352n/a
353n/a May be overridden.
354n/a
355n/a """
356n/a pass
357n/a
358n/a def finish_request(self, request, client_address):
359n/a """Finish one request by instantiating RequestHandlerClass."""
360n/a self.RequestHandlerClass(request, client_address, self)
361n/a
362n/a def shutdown_request(self, request):
363n/a """Called to shutdown and close an individual request."""
364n/a self.close_request(request)
365n/a
366n/a def close_request(self, request):
367n/a """Called to clean up an individual request."""
368n/a pass
369n/a
370n/a def handle_error(self, request, client_address):
371n/a """Handle an error gracefully. May be overridden.
372n/a
373n/a The default is to print a traceback and continue.
374n/a
375n/a """
376n/a print('-'*40, file=sys.stderr)
377n/a print('Exception happened during processing of request from',
378n/a client_address, file=sys.stderr)
379n/a import traceback
380n/a traceback.print_exc()
381n/a print('-'*40, file=sys.stderr)
382n/a
383n/a def __enter__(self):
384n/a return self
385n/a
386n/a def __exit__(self, *args):
387n/a self.server_close()
388n/a
389n/a
390n/aclass TCPServer(BaseServer):
391n/a
392n/a """Base class for various socket-based server classes.
393n/a
394n/a Defaults to synchronous IP stream (i.e., TCP).
395n/a
396n/a Methods for the caller:
397n/a
398n/a - __init__(server_address, RequestHandlerClass, bind_and_activate=True)
399n/a - serve_forever(poll_interval=0.5)
400n/a - shutdown()
401n/a - handle_request() # if you don't use serve_forever()
402n/a - fileno() -> int # for selector
403n/a
404n/a Methods that may be overridden:
405n/a
406n/a - server_bind()
407n/a - server_activate()
408n/a - get_request() -> request, client_address
409n/a - handle_timeout()
410n/a - verify_request(request, client_address)
411n/a - process_request(request, client_address)
412n/a - shutdown_request(request)
413n/a - close_request(request)
414n/a - handle_error()
415n/a
416n/a Methods for derived classes:
417n/a
418n/a - finish_request(request, client_address)
419n/a
420n/a Class variables that may be overridden by derived classes or
421n/a instances:
422n/a
423n/a - timeout
424n/a - address_family
425n/a - socket_type
426n/a - request_queue_size (only for stream sockets)
427n/a - allow_reuse_address
428n/a
429n/a Instance variables:
430n/a
431n/a - server_address
432n/a - RequestHandlerClass
433n/a - socket
434n/a
435n/a """
436n/a
437n/a address_family = socket.AF_INET
438n/a
439n/a socket_type = socket.SOCK_STREAM
440n/a
441n/a request_queue_size = 5
442n/a
443n/a allow_reuse_address = False
444n/a
445n/a def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
446n/a """Constructor. May be extended, do not override."""
447n/a BaseServer.__init__(self, server_address, RequestHandlerClass)
448n/a self.socket = socket.socket(self.address_family,
449n/a self.socket_type)
450n/a if bind_and_activate:
451n/a try:
452n/a self.server_bind()
453n/a self.server_activate()
454n/a except:
455n/a self.server_close()
456n/a raise
457n/a
458n/a def server_bind(self):
459n/a """Called by constructor to bind the socket.
460n/a
461n/a May be overridden.
462n/a
463n/a """
464n/a if self.allow_reuse_address:
465n/a self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
466n/a self.socket.bind(self.server_address)
467n/a self.server_address = self.socket.getsockname()
468n/a
469n/a def server_activate(self):
470n/a """Called by constructor to activate the server.
471n/a
472n/a May be overridden.
473n/a
474n/a """
475n/a self.socket.listen(self.request_queue_size)
476n/a
477n/a def server_close(self):
478n/a """Called to clean-up the server.
479n/a
480n/a May be overridden.
481n/a
482n/a """
483n/a self.socket.close()
484n/a
485n/a def fileno(self):
486n/a """Return socket file number.
487n/a
488n/a Interface required by selector.
489n/a
490n/a """
491n/a return self.socket.fileno()
492n/a
493n/a def get_request(self):
494n/a """Get the request and client address from the socket.
495n/a
496n/a May be overridden.
497n/a
498n/a """
499n/a return self.socket.accept()
500n/a
501n/a def shutdown_request(self, request):
502n/a """Called to shutdown and close an individual request."""
503n/a try:
504n/a #explicitly shutdown. socket.close() merely releases
505n/a #the socket and waits for GC to perform the actual close.
506n/a request.shutdown(socket.SHUT_WR)
507n/a except OSError:
508n/a pass #some platforms may raise ENOTCONN here
509n/a self.close_request(request)
510n/a
511n/a def close_request(self, request):
512n/a """Called to clean up an individual request."""
513n/a request.close()
514n/a
515n/a
516n/aclass UDPServer(TCPServer):
517n/a
518n/a """UDP server class."""
519n/a
520n/a allow_reuse_address = False
521n/a
522n/a socket_type = socket.SOCK_DGRAM
523n/a
524n/a max_packet_size = 8192
525n/a
526n/a def get_request(self):
527n/a data, client_addr = self.socket.recvfrom(self.max_packet_size)
528n/a return (data, self.socket), client_addr
529n/a
530n/a def server_activate(self):
531n/a # No need to call listen() for UDP.
532n/a pass
533n/a
534n/a def shutdown_request(self, request):
535n/a # No need to shutdown anything.
536n/a self.close_request(request)
537n/a
538n/a def close_request(self, request):
539n/a # No need to close anything.
540n/a pass
541n/a
542n/aif hasattr(os, "fork"):
543n/a class ForkingMixIn:
544n/a """Mix-in class to handle each request in a new process."""
545n/a
546n/a timeout = 300
547n/a active_children = None
548n/a max_children = 40
549n/a
550n/a def collect_children(self):
551n/a """Internal routine to wait for children that have exited."""
552n/a if self.active_children is None:
553n/a return
554n/a
555n/a # If we're above the max number of children, wait and reap them until
556n/a # we go back below threshold. Note that we use waitpid(-1) below to be
557n/a # able to collect children in size(<defunct children>) syscalls instead
558n/a # of size(<children>): the downside is that this might reap children
559n/a # which we didn't spawn, which is why we only resort to this when we're
560n/a # above max_children.
561n/a while len(self.active_children) >= self.max_children:
562n/a try:
563n/a pid, _ = os.waitpid(-1, 0)
564n/a self.active_children.discard(pid)
565n/a except ChildProcessError:
566n/a # we don't have any children, we're done
567n/a self.active_children.clear()
568n/a except OSError:
569n/a break
570n/a
571n/a # Now reap all defunct children.
572n/a for pid in self.active_children.copy():
573n/a try:
574n/a pid, _ = os.waitpid(pid, os.WNOHANG)
575n/a # if the child hasn't exited yet, pid will be 0 and ignored by
576n/a # discard() below
577n/a self.active_children.discard(pid)
578n/a except ChildProcessError:
579n/a # someone else reaped it
580n/a self.active_children.discard(pid)
581n/a except OSError:
582n/a pass
583n/a
584n/a def handle_timeout(self):
585n/a """Wait for zombies after self.timeout seconds of inactivity.
586n/a
587n/a May be extended, do not override.
588n/a """
589n/a self.collect_children()
590n/a
591n/a def service_actions(self):
592n/a """Collect the zombie child processes regularly in the ForkingMixIn.
593n/a
594n/a service_actions is called in the BaseServer's serve_forver loop.
595n/a """
596n/a self.collect_children()
597n/a
598n/a def process_request(self, request, client_address):
599n/a """Fork a new subprocess to process the request."""
600n/a pid = os.fork()
601n/a if pid:
602n/a # Parent process
603n/a if self.active_children is None:
604n/a self.active_children = set()
605n/a self.active_children.add(pid)
606n/a self.close_request(request)
607n/a return
608n/a else:
609n/a # Child process.
610n/a # This must never return, hence os._exit()!
611n/a status = 1
612n/a try:
613n/a self.finish_request(request, client_address)
614n/a status = 0
615n/a except Exception:
616n/a self.handle_error(request, client_address)
617n/a finally:
618n/a try:
619n/a self.shutdown_request(request)
620n/a finally:
621n/a os._exit(status)
622n/a
623n/a
624n/aclass ThreadingMixIn:
625n/a """Mix-in class to handle each request in a new thread."""
626n/a
627n/a # Decides how threads will act upon termination of the
628n/a # main process
629n/a daemon_threads = False
630n/a
631n/a def process_request_thread(self, request, client_address):
632n/a """Same as in BaseServer but as a thread.
633n/a
634n/a In addition, exception handling is done here.
635n/a
636n/a """
637n/a try:
638n/a self.finish_request(request, client_address)
639n/a except Exception:
640n/a self.handle_error(request, client_address)
641n/a finally:
642n/a self.shutdown_request(request)
643n/a
644n/a def process_request(self, request, client_address):
645n/a """Start a new thread to process the request."""
646n/a t = threading.Thread(target = self.process_request_thread,
647n/a args = (request, client_address))
648n/a t.daemon = self.daemon_threads
649n/a t.start()
650n/a
651n/a
652n/aif hasattr(os, "fork"):
653n/a class ForkingUDPServer(ForkingMixIn, UDPServer): pass
654n/a class ForkingTCPServer(ForkingMixIn, TCPServer): pass
655n/a
656n/aclass ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
657n/aclass ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
658n/a
659n/aif hasattr(socket, 'AF_UNIX'):
660n/a
661n/a class UnixStreamServer(TCPServer):
662n/a address_family = socket.AF_UNIX
663n/a
664n/a class UnixDatagramServer(UDPServer):
665n/a address_family = socket.AF_UNIX
666n/a
667n/a class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass
668n/a
669n/a class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): pass
670n/a
671n/aclass BaseRequestHandler:
672n/a
673n/a """Base class for request handler classes.
674n/a
675n/a This class is instantiated for each request to be handled. The
676n/a constructor sets the instance variables request, client_address
677n/a and server, and then calls the handle() method. To implement a
678n/a specific service, all you need to do is to derive a class which
679n/a defines a handle() method.
680n/a
681n/a The handle() method can find the request as self.request, the
682n/a client address as self.client_address, and the server (in case it
683n/a needs access to per-server information) as self.server. Since a
684n/a separate instance is created for each request, the handle() method
685n/a can define other arbitrary instance variables.
686n/a
687n/a """
688n/a
689n/a def __init__(self, request, client_address, server):
690n/a self.request = request
691n/a self.client_address = client_address
692n/a self.server = server
693n/a self.setup()
694n/a try:
695n/a self.handle()
696n/a finally:
697n/a self.finish()
698n/a
699n/a def setup(self):
700n/a pass
701n/a
702n/a def handle(self):
703n/a pass
704n/a
705n/a def finish(self):
706n/a pass
707n/a
708n/a
709n/a# The following two classes make it possible to use the same service
710n/a# class for stream or datagram servers.
711n/a# Each class sets up these instance variables:
712n/a# - rfile: a file object from which receives the request is read
713n/a# - wfile: a file object to which the reply is written
714n/a# When the handle() method returns, wfile is flushed properly
715n/a
716n/a
717n/aclass StreamRequestHandler(BaseRequestHandler):
718n/a
719n/a """Define self.rfile and self.wfile for stream sockets."""
720n/a
721n/a # Default buffer sizes for rfile, wfile.
722n/a # We default rfile to buffered because otherwise it could be
723n/a # really slow for large data (a getc() call per byte); we make
724n/a # wfile unbuffered because (a) often after a write() we want to
725n/a # read and we need to flush the line; (b) big writes to unbuffered
726n/a # files are typically optimized by stdio even when big reads
727n/a # aren't.
728n/a rbufsize = -1
729n/a wbufsize = 0
730n/a
731n/a # A timeout to apply to the request socket, if not None.
732n/a timeout = None
733n/a
734n/a # Disable nagle algorithm for this socket, if True.
735n/a # Use only when wbufsize != 0, to avoid small packets.
736n/a disable_nagle_algorithm = False
737n/a
738n/a def setup(self):
739n/a self.connection = self.request
740n/a if self.timeout is not None:
741n/a self.connection.settimeout(self.timeout)
742n/a if self.disable_nagle_algorithm:
743n/a self.connection.setsockopt(socket.IPPROTO_TCP,
744n/a socket.TCP_NODELAY, True)
745n/a self.rfile = self.connection.makefile('rb', self.rbufsize)
746n/a if self.wbufsize == 0:
747n/a self.wfile = _SocketWriter(self.connection)
748n/a else:
749n/a self.wfile = self.connection.makefile('wb', self.wbufsize)
750n/a
751n/a def finish(self):
752n/a if not self.wfile.closed:
753n/a try:
754n/a self.wfile.flush()
755n/a except socket.error:
756n/a # A final socket error may have occurred here, such as
757n/a # the local error ECONNABORTED.
758n/a pass
759n/a self.wfile.close()
760n/a self.rfile.close()
761n/a
762n/aclass _SocketWriter(BufferedIOBase):
763n/a """Simple writable BufferedIOBase implementation for a socket
764n/a
765n/a Does not hold data in a buffer, avoiding any need to call flush()."""
766n/a
767n/a def __init__(self, sock):
768n/a self._sock = sock
769n/a
770n/a def writable(self):
771n/a return True
772n/a
773n/a def write(self, b):
774n/a self._sock.sendall(b)
775n/a with memoryview(b) as view:
776n/a return view.nbytes
777n/a
778n/a def fileno(self):
779n/a return self._sock.fileno()
780n/a
781n/aclass DatagramRequestHandler(BaseRequestHandler):
782n/a
783n/a """Define self.rfile and self.wfile for datagram sockets."""
784n/a
785n/a def setup(self):
786n/a from io import BytesIO
787n/a self.packet, self.socket = self.request
788n/a self.rfile = BytesIO(self.packet)
789n/a self.wfile = BytesIO()
790n/a
791n/a def finish(self):
792n/a self.socket.sendto(self.wfile.getvalue(), self.client_address)