kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Lucas Meneghel Rodrigues <lmr@redhat.com>
To: autotest@test.kernel.org
Cc: kvm@vger.kernel.org
Subject: [PATCH 09/11] Virt: builtin HTTP server for unattended installs
Date: Tue, 11 Oct 2011 18:07:15 -0300	[thread overview]
Message-ID: <1318367237-26081-10-git-send-email-lmr@redhat.com> (raw)
In-Reply-To: <1318367237-26081-1-git-send-email-lmr@redhat.com>

From: Cleber Rosa <crosa@redhat.com>

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

Signed-off-by: Cleber Rosa <crosa@redhat.com>
---
 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.6.4

  parent reply	other threads:[~2011-10-11 21:07 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-10-11 21:07 [PATCH 00/11] [RFC] Libvirt test v2 Lucas Meneghel Rodrigues
2011-10-11 21:07 ` [PATCH 02/11] virt: Introducing virt_test.virt_test class Lucas Meneghel Rodrigues
2011-10-11 21:07 ` [PATCH 03/11] Moving unattended_install test from kvm test to common virt location Lucas Meneghel Rodrigues
2011-10-11 21:07 ` [PATCH 04/11] Moving get_started code to client.virt.virt_utils Lucas Meneghel Rodrigues
2011-10-11 21:07 ` [PATCH 05/11] virt: Introducing libvirt VM class Lucas Meneghel Rodrigues
2011-10-12  6:51   ` [Autotest] " Amos Kong
2011-10-12  8:14   ` Daniel P. Berrange
2011-10-13 17:26     ` Lucas Meneghel Rodrigues
2011-10-11 21:07 ` [PATCH 06/11] virt: Introducing libvirt monitor Lucas Meneghel Rodrigues
2011-10-12  7:48   ` [Autotest] " Amos Kong
2011-10-13 17:12     ` Lucas Meneghel Rodrigues
2011-10-11 21:07 ` [PATCH 07/11] virt.virt_env_process: Add libvirt vm handling Lucas Meneghel Rodrigues
2011-10-11 21:07 ` [PATCH 08/11] client.tests: Introducing libvirt test Lucas Meneghel Rodrigues
2011-10-11 21:07 ` Lucas Meneghel Rodrigues [this message]
2011-10-11 21:07 ` [PATCH 10/11] Virt: support XEN via libvirt and auto url installer Lucas Meneghel Rodrigues
2011-10-11 21:07 ` [PATCH 11/11] Virt: add support for XEN via libvirt installs and auto url Lucas Meneghel Rodrigues

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1318367237-26081-10-git-send-email-lmr@redhat.com \
    --to=lmr@redhat.com \
    --cc=autotest@test.kernel.org \
    --cc=kvm@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).