tools: nfd-status-http-server: serve XML
refs #1690
Change-Id: Ie5de0b8e5041f91cf9bdf1ec7e2c24cde5ffbe38
diff --git a/tools/nfd-status-http-server-files/nfd-status.xsl b/tools/nfd-status-http-server-files/nfd-status.xsl
new file mode 100644
index 0000000..2111ffe
--- /dev/null
+++ b/tools/nfd-status-http-server-files/nfd-status.xsl
@@ -0,0 +1,148 @@
+<xsl:stylesheet version="1.0"
+xmlns="http://www.w3.org/1999/xhtml"
+xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+xmlns:nfd="ndn:/localhost/nfd/status/1">
+
+<xsl:template match="/">
+ <html>
+ <head>
+ <title>NFD Status</title>
+ </head>
+ <body>
+ <xsl:apply-templates/>
+ </body>
+ </html>
+</xsl:template>
+
+<xsl:template match="nfd:generalStatus">
+ <h2>General NFD status</h2>
+ <table>
+ <tr>
+ <td>Version</td>
+ <td><xsl:value-of select="nfd:version"/></td>
+ </tr>
+ <tr>
+ <td>startTime</td>
+ <td><xsl:value-of select="nfd:startTime"/></td>
+ </tr>
+ <tr>
+ <td>currentTime</td>
+ <td><xsl:value-of select="nfd:currentTime"/></td>
+ </tr>
+ <tr>
+ <td>upTime</td>
+ <td><xsl:value-of select="nfd:uptime"/></td>
+ </tr>
+ <tr>
+ <td>nNameTreeEntries</td>
+ <td><xsl:value-of select="nfd:nNameTreeEntries"/></td>
+ </tr>
+ <tr>
+ <td>nFibEntries</td>
+ <td><xsl:value-of select="nfd:nFibEntries"/></td>
+ </tr>
+ <tr>
+ <td>nPitEntries</td>
+ <td><xsl:value-of select="nfd:nPitEntries"/></td>
+ </tr>
+ <tr>
+ <td>nMeasurementsEntries</td>
+ <td><xsl:value-of select="nfd:nMeasurementsEntries"/></td>
+ </tr>
+ <tr>
+ <td>nCsEntries</td>
+ <td><xsl:value-of select="nfd:nCsEntries"/></td>
+ </tr>
+ <tr>
+ <td>nInInterests</td>
+ <td><xsl:value-of select="nfd:packetCounters/nfd:incomingPackets/nfd:nInterests"/></td>
+ </tr>
+ <tr>
+ <td>nOutInterests</td>
+ <td><xsl:value-of select="nfd:packetCounters/nfd:outgoingPackets/nfd:nInterests"/></td>
+ </tr>
+ <tr>
+ <td>nInDatas</td>
+ <td><xsl:value-of select="nfd:packetCounters/nfd:incomingPackets/nfd:nDatas"/></td>
+ </tr>
+ <tr>
+ <td>nOutDatas</td>
+ <td><xsl:value-of select="nfd:packetCounters/nfd:outgoingPackets/nfd:nDatas"/></td>
+ </tr>
+ </table>
+</xsl:template>
+
+<xsl:template match="nfd:channels">
+ <h2>Channels</h2>
+ <table>
+ <xsl:for-each select="nfd:channel">
+ <tr>
+ <td><xsl:value-of select="nfd:localUri"/></td>
+ </tr>
+ </xsl:for-each>
+ </table>
+</xsl:template>
+
+<xsl:template match="nfd:faces">
+ <h2>Faces</h2>
+ <table>
+ <tr style="background-color: #9acd32;">
+ <th>faceID</th>
+ <th>remoteUri</th>
+ <th>localUri</th>
+ <th>nInInterests</th>
+ <th>nInDatas</th>
+ <th>nOutInterests</th>
+ <th>nOutDatas</th>
+ </tr>
+ <xsl:for-each select="nfd:face">
+ <tr>
+ <td><xsl:value-of select="nfd:faceId"/></td>
+ <td><xsl:value-of select="nfd:remoteUri"/></td>
+ <td><xsl:value-of select="nfd:localUri"/></td>
+ <td><xsl:value-of select="nfd:packetCounters/nfd:incomingPackets/nfd:nInterests"/></td>
+ <td><xsl:value-of select="nfd:packetCounters/nfd:incomingPackets/nfd:nDatas"/></td>
+ <td><xsl:value-of select="nfd:packetCounters/nfd:outgoingPackets/nfd:nInterests"/></td>
+ <td><xsl:value-of select="nfd:packetCounters/nfd:outgoingPackets/nfd:nDatas"/></td>
+ </tr>
+ </xsl:for-each>
+ </table>
+</xsl:template>
+
+<xsl:template match="nfd:fib">
+ <h2>FIB</h2>
+ <table>
+ <tr style="background-color: #9acd32;">
+ <th>prefix</th>
+ <th>nextHops</th>
+ </tr>
+ <xsl:for-each select="nfd:fibEntry">
+ <tr>
+ <td style="text-align:left;vertical-align:top;padding:0"><xsl:value-of select="nfd:prefix"/></td>
+ <td>
+ <xsl:for-each select="nfd:nextHops/nfd:nextHop">
+ faceid=<xsl:value-of select="nfd:faceId"/> (cost=<xsl:value-of select="nfd:cost"/>);
+ </xsl:for-each>
+ </td>
+ </tr>
+ </xsl:for-each>
+ </table>
+</xsl:template>
+
+<xsl:template match="nfd:strategyChoices">
+ <h2>Strategy Choices</h2>
+ <table>
+ <tr style="background-color: #9acd32;">
+ <th>Namespace</th>
+ <th>Strategy Name</th>
+ </tr>
+ <xsl:for-each select="nfd:strategyChoice">
+ <tr>
+ <td><xsl:value-of select="nfd:namespace"/></td>
+ <td><xsl:value-of select="nfd:strategy/nfd:name"/></td>
+ </tr>
+ </xsl:for-each>
+ </table>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/tools/nfd-status-http-server-files/robots.txt b/tools/nfd-status-http-server-files/robots.txt
new file mode 100644
index 0000000..1f53798
--- /dev/null
+++ b/tools/nfd-status-http-server-files/robots.txt
@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /
diff --git a/tools/nfd-status-http-server.py b/tools/nfd-status-http-server.py
index 6e0f167..33adb48 100755
--- a/tools/nfd-status-http-server.py
+++ b/tools/nfd-status-http-server.py
@@ -24,7 +24,8 @@
NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
"""
-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from BaseHTTPServer import HTTPServer
+from SimpleHTTPServer import SimpleHTTPRequestHandler
from SocketServer import ThreadingMixIn
import sys
import commands
@@ -34,84 +35,63 @@
import cgi
import argparse
import socket
+import os
-class StatusHandler(BaseHTTPRequestHandler):
+class StatusHandler(SimpleHTTPRequestHandler):
""" The handler class to handle requests."""
def do_GET(self):
# get the url info to decide how to respond
parsedPath = urlparse.urlparse(self.path)
- resultMessage = ""
- if parsedPath.path == "/robots.txt":
- if self.server.robots == False:
- # return User-agent: * Disallow: / to disallow robots
- resultMessage = "User-agent: * \nDisallow: /\n"
+ if parsedPath.path == "/":
+ # get current nfd status, and use it as result message
+ (res, resultMessage) = self.getNfdStatus()
+ self.send_response(200)
+ if res == 0:
+ self.send_header("Content-type", "text/xml; charset=UTF-8")
+ else:
+ self.send_header("Content-type", "text/html; charset=UTF-8")
+
+ self.end_headers()
+ self.wfile.write(resultMessage)
+ elif parsedPath.path == "/robots.txt" and self.server.robots == True:
+ resultMessage = ""
self.send_response(200)
self.send_header("Content-type", "text/plain")
- elif parsedPath.path == "/":
- # get current nfd status, and use it as result message
- resultMessage = self.getNfdStatus()
- self.send_response(200)
- self.send_header("Content-type", "text/html; charset=UTF-8")
+ self.end_headers()
+ self.wfile.write(resultMessage)
else:
- # non-existing content
- resultMessage = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 '\
- + 'Transitional//EN" '\
- + '"http://www.w3.org/TR/html4/loose.dtd">\n'\
- + '<html><head><title>Object not '\
- + 'found!</title><meta http-equiv="Content-type" ' \
- + 'content="text/html;charset=UTF-8"></head>\n'\
- + '<body><h1>Object not found!</h1>'\
- + '<p>The requested URL was not found on this server.</p>'\
- + '<h2>Error 404</h2>'\
- + '</body></html>'
- self.send_response(404)
- self.send_header("Content-type", "text/html; charset=UTF-8")
-
- self.end_headers()
- self.wfile.write(resultMessage)
+ SimpleHTTPRequestHandler.do_GET(self)
def log_message(self, format, *args):
if self.server.verbose:
logging.info("%s - %s\n" % (self.address_string(),
- format % args))
+ format % args))
def getNfdStatus(self):
"""
- This function tries to call nfd-status command
- to get nfd's current status, after convert it
- to html format, return it to the caller
+ This function is to call nfd-status command
+ to get xml format output
"""
- (res, output) = commands.getstatusoutput('nfd-status')
-
- htmlStr = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional'\
- + '//EN" "http://www.w3.org/TR/html4/loose.dtd">\n'\
- + '<html><head><title>NFD status</title>'\
- + '<meta http-equiv="Content-type" content="text/html;'\
- + 'charset=UTF-8"></head>\n<body>'
+ (res, output) = commands.getstatusoutput('nfd-status -x')
if res == 0:
- # parse the output
- buf = StringIO.StringIO(output)
- firstLine = 0
- for line in buf:
- if line.endswith(":\n"):
- if firstLine != 0:
- htmlStr += "</ul>\n"
- firstLine += 1
- htmlStr += "<b>" + cgi.escape(line.strip()) + "</b><br>\n"\
- + "<ul>\n"
- continue
- line = line.strip()
- htmlStr += "<li>" + cgi.escape(line) + "</li>\n"
- buf.close()
- htmlStr += "</ul>\n"
+ # add the xml-stylesheet processing instruction after the 1st '>' symbol
+ newLineIndex = output.index('>') + 1
+ resultStr = output[:newLineIndex]\
+ + "<?xml-stylesheet type=\"text/xsl\" href=\"nfd-status.xsl\"?>"\
+ + output[newLineIndex:]
+ return (res, resultStr)
else:
+ htmlStr = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional'\
+ + '//EN" "http://www.w3.org/TR/html4/loose.dtd">\n'\
+ + '<html><head><title>NFD status</title>'\
+ + '<meta http-equiv="Content-type" content="text/html;'\
+ + 'charset=UTF-8"></head>\n<body>'
# return connection error code
htmlStr = htmlStr + "<p>Cannot connect to NFD,"\
+ " Code = " + str(res) + "</p>\n"
- htmlStr = htmlStr + "</body></html>"
- return htmlStr
-
+ htmlStr = htmlStr + "</body></html>"
+ return (res, htmlStr)
class ThreadHttpServer(ThreadingMixIn, HTTPServer):
""" Handle requests using threads """
@@ -162,6 +142,8 @@
help="Specify the HTTP server IP address.")
parser.add_argument("-r", default=False, dest="robots", action="store_true",
help="Enable HTTP robots to crawl; disabled by default.")
+ parser.add_argument("-f", default="/usr/local/share/ndn/", metavar="Server Directory", dest="serverDir",
+ help="Specify the working directory of nfd-status-http-server, default is /usr/local/share/ndn.")
parser.add_argument("-v", default=False, dest="verbose", action="store_true",
help="Verbose mode.")
parser.add_argument("--version", default=False, dest="version", action="store_true",
@@ -177,6 +159,9 @@
localAddr = args["addr"]
verbose = args["verbose"]
robots = args["robots"]
+ serverDirectory = args["serverDir"]
+
+ os.chdir(serverDirectory)
# setting log message format
logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s',