5 Copyright (c) 2014-2018, Regents of the University of California, 6 Arizona Board of Regents, 7 Colorado State University, 8 University Pierre & Marie Curie, Sorbonne University, 9 Washington University in St. Louis, 10 Beijing Institute of Technology, 11 The University of Memphis. 13 This file is part of NFD (Named Data Networking Forwarding Daemon). 14 See AUTHORS.md for complete list of NFD authors and contributors. 16 NFD is free software: you can redistribute it and/or modify it under the terms 17 of the GNU General Public License as published by the Free Software Foundation, 18 either version 3 of the License, or (at your option) any later version. 20 NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 21 without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 22 PURPOSE. See the GNU General Public License for more details. 24 You should have received a copy of the GNU General Public License along with 25 NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>. 28 from http.server
import HTTPServer, SimpleHTTPRequestHandler
29 from socketserver
import ThreadingMixIn
30 import argparse, ipaddress, os, socket, subprocess
34 """ The handler class to handle requests """ 38 elif self.
path ==
"/robots.txt" and self.server.allowRobots:
43 def __serveReport(self):
44 """ Obtain XML-formatted NFD status report and send it back as response body """ 47 output = subprocess.check_output([
"nfdc",
"status",
"report",
"xml"], universal_newlines=
True)
48 except OSError
as err:
49 super().
log_message(
"error invoking nfdc: {}".format(err))
51 except subprocess.CalledProcessError
as err:
52 super().
log_message(
"error invoking nfdc: command exited with status {}".format(err.returncode))
53 self.send_error(504,
"Cannot connect to NFD (code {})".format(err.returncode))
57 pos = output.index(
">") + 1
59 +
'<?xml-stylesheet type="text/xsl" href="nfd-status.xsl"?>'\
61 self.send_response(200)
62 self.send_header(
"Content-Type",
"text/xml; charset=UTF-8")
64 self.wfile.write(xml.encode())
68 if self.server.verbose:
73 """ Handle requests using threads """ 74 def __init__(self, bindAddr, port, handler, allowRobots=False, verbose=False):
77 if bindAddr.version == 6:
81 super().
__init__((str(bindAddr), port), handler)
86 """ Validate IP address """ 88 value = ipaddress.ip_address(arg)
90 raise argparse.ArgumentTypeError(
"{!r} is not a valid IP address".format(arg))
94 """ Validate port number """ 99 if value < 0
or value > 65535:
100 raise argparse.ArgumentTypeError(
"{!r} is not a valid port number".format(arg))
103 parser = argparse.ArgumentParser(description=
"Serves NFD status page via HTTP")
104 parser.add_argument(
"-V",
"--version", action=
"version", version=
"@VERSION@")
105 parser.add_argument(
"-a",
"--address", default=
"127.0.0.1", type=ipAddress, metavar=
"ADDR",
106 help=
"bind to this IP address (default: %(default)s)")
107 parser.add_argument(
"-p",
"--port", default=8080, type=portNumber,
108 help=
"bind to this port number (default: %(default)s)")
109 parser.add_argument(
"-f",
"--workdir", default=
"@DATAROOTDIR@/ndn", metavar=
"DIR",
110 help=
"server's working directory (default: %(default)s)")
111 parser.add_argument(
"-r",
"--robots", action=
"store_true",
112 help=
"allow crawlers and other HTTP bots")
113 parser.add_argument(
"-v",
"--verbose", action=
"store_true",
114 help=
"turn on verbose logging")
115 args = parser.parse_args()
117 os.chdir(args.workdir)
120 allowRobots=args.robots, verbose=args.verbose)
122 if httpd.address_family == socket.AF_INET6:
123 url =
"http://[{}]:{}" 126 print(
"Server started at", url.format(*httpd.server_address))
129 httpd.serve_forever()
130 except KeyboardInterrupt:
135 if __name__ ==
"__main__":
def __init__(self, bindAddr, port, handler, allowRobots=False, verbose=False)
def log_message(self, args)