blob: ccfaee572bc721a2d1cab6bbda0862d1bf218f3e [file] [log] [blame]
Chengyu Fanb07788a2014-03-31 12:15:36 -06001#!/usr/bin/env python2.7
2
3from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
4from SocketServer import ThreadingMixIn
5import sys
6import commands
7import StringIO
8import urlparse
9import logging
10import cgi
11import argparse
Chengyu Fane25b0f02014-04-05 21:42:40 -060012import socket
Chengyu Fanb07788a2014-03-31 12:15:36 -060013
14
15class StatusHandler(BaseHTTPRequestHandler):
16 """ The handler class to handle requests."""
17 def do_GET(self):
18 # get the url info to decide how to respond
19 parsedPath = urlparse.urlparse(self.path)
20 resultMessage = ""
21 if parsedPath.path == "/robots.txt":
22 if self.server.robots == False:
23 # return User-agent: * Disallow: / to disallow robots
24 resultMessage = "User-agent: * \nDisallow: /\n"
25 self.send_response(200)
26 self.send_header("Content-type", "text/plain")
27 elif parsedPath.path == "/":
28 # get current nfd status, and use it as result message
29 resultMessage = self.getNfdStatus()
30 self.send_response(200)
31 self.send_header("Content-type", "text/html; charset=UTF-8")
32 else:
33 # non-existing content
34 resultMessage = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 '\
35 + 'Transitional//EN" '\
36 + '"http://www.w3.org/TR/html4/loose.dtd">\n'\
37 + '<html><head><title>Object not '\
38 + 'found!</title><meta http-equiv="Content-type" ' \
39 + 'content="text/html;charset=UTF-8"></head>\n'\
40 + '<body><h1>Object not found!</h1>'\
41 + '<p>The requested URL was not found on this server.</p>'\
42 + '<h2>Error 404</h2>'\
43 + '</body></html>'
44 self.send_response(404)
45 self.send_header("Content-type", "text/html; charset=UTF-8")
46
47 self.end_headers()
48 self.wfile.write(resultMessage)
49
Chengyu Fanb07788a2014-03-31 12:15:36 -060050 def log_message(self, format, *args):
51 if self.server.verbose:
Chengyu Fane25b0f02014-04-05 21:42:40 -060052 logging.info("%s - %s\n" % (self.address_string(),
53 format % args))
Chengyu Fanb07788a2014-03-31 12:15:36 -060054
55 def getNfdStatus(self):
56 """
57 This function tries to call nfd-status command
58 to get nfd's current status, after convert it
59 to html format, return it to the caller
60 """
61 (res, output) = commands.getstatusoutput('nfd-status')
62
63 htmlStr = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional'\
64 + '//EN" "http://www.w3.org/TR/html4/loose.dtd">\n'\
65 + '<html><head><title>NFD status</title>'\
66 + '<meta http-equiv="Content-type" content="text/html;'\
67 + 'charset=UTF-8"></head>\n<body>'
68 if res == 0:
69 # parse the output
70 buf = StringIO.StringIO(output)
71 firstLine = 0
72 for line in buf:
73 if line.endswith(":\n"):
74 if firstLine != 0:
75 htmlStr += "</ul>\n"
76 firstLine += 1
77 htmlStr += "<b>" + cgi.escape(line.strip()) + "</b><br>\n"\
78 + "<ul>\n"
79 continue
80 line = line.strip()
81 htmlStr += "<li>" + cgi.escape(line) + "</li>\n"
82 buf.close()
83 htmlStr += "</ul>\n"
84 else:
85 # return connection error code
86 htmlStr = htmlStr + "<p>Cannot connect to NFD,"\
87 + " Code = " + str(res) + "</p>\n"
88 htmlStr = htmlStr + "</body></html>"
89 return htmlStr
90
91
Chengyu Fane25b0f02014-04-05 21:42:40 -060092class ThreadHttpServer(ThreadingMixIn, HTTPServer):
93 """ Handle requests using threads """
Chengyu Fanb07788a2014-03-31 12:15:36 -060094 def __init__(self, server, handler, verbose=False, robots=False):
Chengyu Fane25b0f02014-04-05 21:42:40 -060095 serverAddr = server[0]
96 # socket.AF_UNSPEC is not supported, check whether it is v6 or v4
97 ipType = self.getIpType(serverAddr)
98 if ipType == socket.AF_INET6:
99 self.address_family = socket.AF_INET6
100 elif ipType == socket.AF_INET:
101 self.address_family == socket.AF_INET
102 else:
103 logging.error("The input IP address is neither IPv6 nor IPv4")
104 sys.exit(2)
105
Chengyu Fanb07788a2014-03-31 12:15:36 -0600106 try:
107 HTTPServer.__init__(self, server, handler)
108 except Exception as e:
109 logging.error(str(e))
110 sys.exit(2)
111 self.verbose = verbose
112 self.robots = robots
113
Chengyu Fane25b0f02014-04-05 21:42:40 -0600114 def getIpType(self, ipAddr):
115 """ Get ipAddr's address type """
116 # if ipAddr is an IPv6 addr, return AF_INET6
117 try:
118 socket.inet_pton(socket.AF_INET6, ipAddr)
119 return socket.AF_INET6
120 except socket.error:
121 pass
122 # if ipAddr is an IPv4 addr return AF_INET, if not, return None
123 try:
124 socket.inet_pton(socket.AF_INET, ipAddr)
125 return socket.AF_INET
126 except socket.error:
127 return None
128
Chengyu Fanb07788a2014-03-31 12:15:36 -0600129
130# main function to start
131def httpServer():
132 parser = argparse.ArgumentParser()
133 parser.add_argument("-p", type=int, metavar="port number",
134 help="Specify the HTTP server port number, default is 8080.",
135 dest="port", default=8080)
Chengyu Fane25b0f02014-04-05 21:42:40 -0600136 # if address is not specified, use 127.0.0.1
137 parser.add_argument("-a", default="127.0.0.1", metavar="IP address", dest="addr",
Chengyu Fanb07788a2014-03-31 12:15:36 -0600138 help="Specify the HTTP server IP address.")
139 parser.add_argument("-r", default=False, dest="robots", action="store_true",
140 help="Enable HTTP robots to crawl; disabled by default.")
141 parser.add_argument("-v", default=False, dest="verbose", action="store_true",
142 help="Verbose mode.")
143
144 args = vars(parser.parse_args())
145 localPort = args["port"]
146 localAddr = args["addr"]
147 verbose = args["verbose"]
148 robots = args["robots"]
149
150 # setting log message format
151 logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s',
152 level=logging.INFO)
153
Chengyu Fane25b0f02014-04-05 21:42:40 -0600154 # if port is invalid, exit
Chengyu Fanb07788a2014-03-31 12:15:36 -0600155 if localPort <= 0 or localPort > 65535:
156 logging.error("Specified port number is invalid")
157 sys.exit(2)
158
Chengyu Fane25b0f02014-04-05 21:42:40 -0600159 httpd = ThreadHttpServer((localAddr, localPort), StatusHandler,
Chengyu Fanb07788a2014-03-31 12:15:36 -0600160 verbose, robots)
Chengyu Fane25b0f02014-04-05 21:42:40 -0600161 httpServerAddr = ""
162 if httpd.address_family == socket.AF_INET6:
163 httpServerAddr = "http://[%s]:%s" % (httpd.server_address[0],
164 httpd.server_address[1])
165 else:
166 httpServerAddr = "http://%s:%s" % (httpd.server_address[0],
167 httpd.server_address[1])
Chengyu Fanb07788a2014-03-31 12:15:36 -0600168
Chengyu Fane25b0f02014-04-05 21:42:40 -0600169 logging.info("Server started - at %s" % httpServerAddr)
Chengyu Fanb07788a2014-03-31 12:15:36 -0600170
171 try:
172 httpd.serve_forever()
173 except KeyboardInterrupt:
174 pass
175
Chengyu Fanb07788a2014-03-31 12:15:36 -0600176 httpd.server_close()
177
Chengyu Fane25b0f02014-04-05 21:42:40 -0600178 logging.info("Server stopped")
Chengyu Fanb07788a2014-03-31 12:15:36 -0600179
180
181if __name__ == '__main__':
182 httpServer()