[PATCH 09/16] Virt: builtin HTTP server for unattended installs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Cleber Rosa <crosa@xxxxxxxxxx>

This adds a simple HTTP server that is good enough to support unattended
installs. Tested serving kickstart files and RHEL/Fedora content to
anaconda.

Signed-off-by: Cleber Rosa <crosa@xxxxxxxxxx>
---
 client/virt/virt_http_server.py |  124 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 124 insertions(+), 0 deletions(-)
 create mode 100644 client/virt/virt_http_server.py

diff --git a/client/virt/virt_http_server.py b/client/virt/virt_http_server.py
new file mode 100644
index 0000000..286285a
--- /dev/null
+++ b/client/virt/virt_http_server.py
@@ -0,0 +1,124 @@
+import os, posixpath, urlparse, urllib, logging
+import BaseHTTPServer, SimpleHTTPServer
+
+
+class HTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+
+    def do_GET(self):
+        """
+        Serve a GET request.
+        """
+        range = self.parse_header_byte_range()
+        if range:
+            f = self.send_head_range(range[0], range[1])
+            if f:
+                self.copyfile_range(f, self.wfile, range[0], range[1])
+                f.close()
+        else:
+            f = self.send_head()
+            if f:
+                self.copyfile(f, self.wfile)
+                f.close()
+
+
+    def parse_header_byte_range(self):
+        range_param = 'Range'
+        range_discard = 'bytes='
+        if self.headers.has_key(range_param):
+            range = self.headers.get(range_param)
+            if range.startswith(range_discard):
+                range = range[len(range_discard):]
+                begin, end = range.split('-')
+                return (int(begin), int(end))
+        return None
+
+
+    def copyfile_range(self, source_file, output_file, range_begin, range_end):
+        """
+        Copies a range of a file to destination.
+        """
+        range_size = range_end - range_begin + 1
+        source_file.seek(range_begin)
+        buf = source_file.read(range_size)
+        output_file.write(buf)
+
+
+    def send_head_range(self, range_begin, range_end):
+        path = self.translate_path(self.path)
+        f = None
+        if os.path.isdir(path):
+            for index in "index.html", "index.htm":
+                index = os.path.join(path, index)
+                if os.path.exists(index):
+                    path = index
+                    break
+            else:
+                return self.list_directory(path)
+        ctype = self.guess_type(path)
+        try:
+            # Always read in binary mode. Opening files in text mode may cause
+            # newline translations, making the actual size of the content
+            # transmitted *less* than the content-length!
+            f = open(path, 'rb')
+        except IOError:
+            self.send_error(404, "File not found")
+            return None
+        self.send_response(206, "Partial Content")
+        file_size = str(os.fstat(f.fileno())[6])
+        range_size = str(range_end - range_begin + 1)
+        self.send_header("Accept-Ranges", "bytes")
+        self.send_header("Content-Length", range_size)
+        self.send_header("Content-Range", "bytes %s-%s/%s" % (range_begin,
+                                                              range_end,
+                                                              file_size))
+        self.send_header("Content-type", ctype)
+        self.end_headers()
+        return f
+
+
+    def translate_path(self, path):
+        """
+        Translate a /-separated PATH to the local filename syntax.
+
+        Components that mean special things to the local file system
+        (e.g. drive or directory names) are ignored.  (XXX They should
+        probably be diagnosed.)
+
+        """
+        # abandon query parameters
+        path = urlparse.urlparse(path)[2]
+        path = posixpath.normpath(urllib.unquote(path))
+        words = path.split('/')
+        words = filter(None, words)
+        path = self.server.cwd
+        for word in words:
+            drive, word = os.path.splitdrive(word)
+            head, word = os.path.split(word)
+            if word in (os.curdir, os.pardir): continue
+            path = os.path.join(path, word)
+        return path
+
+
+    def log_message(self, format, *args):
+        logging.debug("builtin http server handling request from %s: %s" %
+                      (self.address_string(), format%args))
+
+
+def http_server(port=8000, cwd=None, terminate_callable=None):
+    http = BaseHTTPServer.HTTPServer(('', port), HTTPRequestHandler)
+    if cwd is None:
+        cwd = os.getcwd()
+    http.cwd = cwd
+
+    while True:
+        if terminate_callable is not None:
+            terminate = terminate_callable()
+        else:
+            terminate = False
+
+        if not terminate:
+            http.handle_request()
+
+
+if __name__ == '__main__':
+    http_server()
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux