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
next prev 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).