You are not logged in.

#26 2009-12-11 16:04:09

helpvampire
Member
Registered: 2009-08-10
Posts: 32

Re: quickserve - easy ad-hoc file sharing

OK, thanks.

Offline

#27 2009-12-11 16:10:39

helpvampire
Member
Registered: 2009-08-10
Posts: 32

Re: quickserve - easy ad-hoc file sharing

btw about that bug I found in powerpill about it downloading the packages but not running pacman I think it might be because I pressed a button while it was running and it hiden pacman's output.

Offline

#28 2009-12-21 15:33:00

Army
Member
Registered: 2007-12-07
Posts: 1,784

Re: quickserve - easy ad-hoc file sharing

Xyne, did you also think about a server, which provides a site to upload files? I'd love to have sth like that, so others can send me files. I know there's always a security risk, but what about you combine it with quixand?

Offline

#29 2009-12-21 22:37:45

N30N
Member
Registered: 2007-04-08
Posts: 273

Re: quickserve - easy ad-hoc file sharing

Another similar project is woof.

Offline

#30 2009-12-21 23:19:00

Xyne
Moderator/TU
Registered: 2008-08-03
Posts: 6,380
Website

Re: quickserve - easy ad-hoc file sharing

@Army
That might be relatively easy to do with a multipart form. Combining it with quixand would be left to the user along with all other security concerns (plaintext file transfers, etc). I'll give this some thought when I have the time.

@N3ON
I wasn't aware of woof either, but from the description it seems "limited" to a single file.


My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

#31 2009-12-22 12:43:26

Bob Day
Member
Registered: 2005-11-26
Posts: 43

Re: quickserve - easy ad-hoc file sharing

Xyne wrote:

...

@N3ON
I wasn't aware of woof either, but from the description it seems "limited" to a single file.

Woof is indeed "limited" to a single file, if you like to transfer more files woof combines files inside directories into a tar/zip/rar/... on the fly.
In my opinion it would be really cool if quickserve could get a download-link behind the dir-listing to call woof.

hmmm, this sounds like a feature request...is that allowed? ...anyways, thanks for this fine app.

Offline

#32 2009-12-22 13:41:45

Army
Member
Registered: 2007-12-07
Posts: 1,784

Re: quickserve - easy ad-hoc file sharing

Xyne wrote:

@Army
That might be relatively easy to do with a multipart form. Combining it with quixand would be left to the user along with all other security concerns (plaintext file transfers, etc). I'll give this some thought when I have the time.

Cool, thanks :-)

Offline

#33 2010-01-09 17:29:47

cool
Member
Registered: 2008-09-12
Posts: 111
Website

Re: quickserve - easy ad-hoc file sharing

I am using this program from past 15days and Its very useful.Good work from Developer/coder

however, I have just one request

Please make directory listing more readable currently its very difficult to view files and directories.

Firefox listing style:
e56cb363041800.gif

quickserv listing style:
52657d63041802.gif

Hoping you would make it more better:D

Last edited by cool (2010-01-09 17:31:52)

Offline

#34 2010-01-09 22:30:51

FSX
Member
Registered: 2009-08-06
Posts: 57

Re: quickserve - easy ad-hoc file sharing

Hey, I changed some things and added some small things. smile

Screenshot:

2010-01-09_232733_1280x800.jpg

Code:

#!/usr/bin/env python

# Copyright (C) 2009  Xyne
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

# METADATA
# Version: 2.3


from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from hashlib import md5
from mimetypes import guess_type
import os.path
from optparse import OptionParser
from urllib import quote, unquote


class QuickServeHandler(BaseHTTPRequestHandler):

    def allow(self):
        username = options.username
        password = options.password

        if username and password:
            if 'Authorization' in self.headers and self.headers['Authorization'][:7] == 'Digest ':
                #client_username = None
                client_response = None
                #realm = None
                nonce = None

                for field in self.headers['Authorization'][7:].split(', '):
                    #if field[:10] == 'username="':
                    #    client_username = field[10:-1].replace('\"', '"')
                    #el
                    if field[:10] == 'response="':
                        client_response = field[10:-1]
                    #elif field[:7] == 'realm="':
                    #    realm = field[7:-1]
                    elif field[:7] == 'nonce="':
                        nonce = field[7:-1]

                if client_response != None and nonce != None:
                    m = md5()
                    m.update(username + ':' + self.address_string() + ':' + password)
                    ha1 = m.hexdigest()
                    m = md5()
                    m.update('GET:' + self.path)
                    ha2 = m.hexdigest()
                    m = md5()
                    m.update(ha1 + ':' + nonce + ':' + ha2)
                    response = m.hexdigest()

                    if response == client_response:
                        return True

            return False
        elif not username and not password:
            return True

        return False

    def do_GET(self):
        if not self.allow():
            self.send_response(401)
            self.send_header('WWW-Authenticate', 'Digest realm="' + self.address_string() + '"')
            self.send_header('Connection', 'close')
            self.end_headers()
            return

        global paths

        if self.path == '/':
            self.send_response(200)
            self.send_header('Content-type', 'text/html; charset=UTF-8')
            self.end_headers()
            html = generate_html(None, sorted(paths.keys()))
            self.wfile.write(safe_encode_utf8(html))
            return
        else:
            splitpath = self.path[1:].split(os.sep,1)
            if splitpath[0] in paths:
                if splitpath[0] == self.path[1:]:
                    fpath = paths[splitpath[0]]
                elif len(splitpath) == 2:
                    fpath = os.path.join(paths[splitpath[0]], splitpath[1])
                else:
                    fpath = None
                if fpath:
                    fpath = unquote(fpath)
                if os.path.isfile(fpath):
                    self.transfer_file(fpath)
                    return
                elif os.path.isdir(fpath):
                    dirs, files = get_dirs_and_files(fpath)
                    html = generate_html(self.path, map(lambda x: os.path.join(self.path, x), dirs + files), True)
                    self.send_response(200)
                    self.send_header('Content-type', 'text/html; charset=UTF-8')
                    self.end_headers()
                    self.wfile.write( safe_encode_utf8(html) )
                    return

        self.send_response(404)
        self.send_header('Connection', 'close')
        self.end_headers()

    def do_POST(self):
        self.send_response(403)
        self.send_header('Connection', 'close')
        self.end_headers()

    def transfer_file(self, fpath):
        self.send_response(200)
        size = os.path.getsize(fpath)
        range_start = 0
        range_end = size - 1
        mimetype = guess_type(fpath)

        if not mimetype:
            mimetype = 'application/octet-stream'

        self.send_header('Accept-Ranges', 'bytes')
        self.send_header('Content-Type', mimetype)

        if 'range' in self.headers:
            s, e = self.headers['range'][6:].split('-', 1)
            if len(s) > 0:
                range_start = int(s)
            if len(e) > 0:
                range_end = int(e)

        self.send_header('Content-Range', 'bytes ' + str(range_start) + '-' + str(range_end) + '/' + str(size))
        self.send_header('Content-Length', range_end - range_start + 1)
        self.end_headers()

        f = open(fpath, 'rb')
        f.seek(range_start, 0)
        step = 4096
        total = 0

        while step > 0:
            if range_start + step > range_end + 1:
                step = range_end - range_start + 1
            try:
                self.wfile.write(f.read(step))
            except:
                break
            total += step
            range_start += step

        f.close()


def safe_encode_utf8(text):
    try:
        return text.encode('utf-8')
    except UnicodeDecodeError:
        return text


def get_dirs_and_files(path):
    if os.path.isdir(path):
        paths = os.listdir(path)
        return sorted(filter(lambda x: os.path.isdir(os.path.join(path,x)), paths)), \
            sorted(filter(lambda x: os.path.isfile(os.path.join(path,x)), paths))
    elif os.path.isfile(path):
        return [], [os.path.basename(path)]
    else:
        return [], []


def generate_html(title, urls, backlink=False):

    if title is None:
        title = '/'
    else:
        title = title

    if backlink and title != '/':
        backlink = ' <a href="/%s">[Back]</a>' % \
            '/'.join(title.split('/')[1:-1])
    else:
        backlink = ''

    filelist_html = ''

    for url in urls:
        #url = quote(url)
        filelist_html += '''        <li><a href="%s">%s</a></li>\n''' % \
            (url, os.path.basename(url))

    if len(urls) == 0:
        filelist_html = '<li>No files found.</li>'

    return '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
    <title>%(title)s - Quickserve</title>
    <style type="text/css">
        html, body { background-color: #fff;padding: 0;margin: 0 }
        body { font-size: 85%%;line-height: 1.5em;color: #222;
               font-family: "Lucida Grande", "Lucida Sans Unicode",
                            "Lucida Sans", Verdana, Arial, sans-serif }
        #wrapper { margin: 0 auto;width: 90%% }
        h1 { font-weight: normal;color: #333;margin-bottom: 0.5em;
             font-size: 3em;line-height: 1em }
        ul { margin:0 0.5em 1.5em;padding: 0 0 2em 2.5em;
             list-style-type: square }
        h1 a { font-size: 0.5em;text-decoration: none }
    </style>
</head>
<body>

<div id="wrapper">
    <h1>%(title)s%(backlink)s</h1>
    <ul>
%(filelist)s    </ul>
</div>

</body>
</html>
''' % {'title': unquote(title), 'filelist': filelist_html, 'backlink': backlink}


def main(address='localhost', port=8080):
    try:
        server = HTTPServer((address, port), QuickServeHandler)
        print 'Started httpserver on %s:%d...' % (address, port)
        server.serve_forever()
    except KeyboardInterrupt:
        print '^C received, shutting down server'
        server.socket.close()


if __name__ == '__main__':
    myname = 'quickserve'
    parser = OptionParser(description='%s - a simple HTTP server for quickly'
                                      ' sharing files' % myname,
                          usage='%s [options] [paths]' % myname)
    parser.add_option('-b', '--bind', dest='address', default='',
                      action='store',
                      help='Bind the server to this address. By default the'
                           'server will listen on all interfaces.')
    parser.add_option('-p', '--port', dest='port', default=8080, type='int',
                      action='store',
                      help='Set the server port (default: 8080)')
    parser.add_option('-u', '--username', dest='username', action='store',
                      help='Set authentication username.')
    parser.add_option('--password', dest='password', action='store',
                      help='Set authentication password.')
    (options, args) = parser.parse_args()

    global paths, username, password

    username = options.username
    password = options.password
    paths = {}

    for a in args:
        a = os.path.abspath(a)
        paths[os.path.basename(a)] = a

    main(options.address, options.port)

Offline

#35 2010-01-09 23:24:26

Xyne
Moderator/TU
Registered: 2008-08-03
Posts: 6,380
Website

Re: quickserve - easy ad-hoc file sharing

I've just finished adding sizes and mtimes, along with the link to the parent directory. I'll have a look at what FSX has added and merge anything that I find useful.

*edit*

I've merged some of FSX's changes into Quickserve (inclusion of DOCTYPE string, some CSS styles, inclusion of header, name of parent directory link).

Thanks, FSX.

Last edited by Xyne (2010-01-10 01:09:20)


My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

#36 2010-01-10 03:32:20

Pnevma
Member
Registered: 2008-04-11
Posts: 112

Re: quickserve - easy ad-hoc file sharing

It doesn't seem to play nice with folders that have spaces in their names. But besides that, it's great.

I'm using the latest revision and haven't tried any of the previous ones.

----------------------------------------
----------------------------------------
Exception happened during processing of request from ('192.168.1.100', 53860)
Traceback (most recent call last):
  File "/usr/lib/python2.6/SocketServer.py", line 281, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/lib/python2.6/SocketServer.py", line 307, in process_request
    self.finish_request(request, client_address)
  File "/usr/lib/python2.6/SocketServer.py", line 320, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib/python2.6/SocketServer.py", line 615, in __init__
    self.handle()
  File "/usr/lib/python2.6/BaseHTTPServer.py", line 329, in handle
    self.handle_one_request()
  File "/usr/lib/python2.6/BaseHTTPServer.py", line 323, in handle_one_request
    method()
  File "/usr/bin/quickserve", line 104, in do_GET
    html = get_html(self.path, dirs + files)
  File "/usr/bin/quickserve", line 198, in get_html
    stat = os.stat(upath)
OSError: [Errno 2] No such file or directory: '//home/timothy/Misc/Music/Albums/Carbon%20Based%20Lifeforms/Hydroponic Garden'

Offline

#37 2010-01-10 03:43:56

Xyne
Moderator/TU
Registered: 2008-08-03
Posts: 6,380
Website

Re: quickserve - easy ad-hoc file sharing

@Pnevma
Too bad that you didn't try the previous version... the space bug was introduced in the last update. I missed an "unquote" when changing around one of the functions. tongue

Please try the latest version and confirm that it works.

Last edited by Xyne (2010-01-10 03:44:07)


My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

#38 2010-01-10 03:53:14

Pnevma
Member
Registered: 2008-04-11
Posts: 112

Re: quickserve - easy ad-hoc file sharing

Yeah, that's what I figured tongue

I just tried the new version and can confirm that it's fixed. Thanks!

Offline

#39 2010-01-10 04:07:06

Xyne
Moderator/TU
Registered: 2008-08-03
Posts: 6,380
Website

Re: quickserve - easy ad-hoc file sharing

Thanks for reporting the bug and confirming the fix.


My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

#40 2010-01-10 12:37:36

makimaki
Member
From: Ireland
Registered: 2009-04-02
Posts: 109

Re: quickserve - easy ad-hoc file sharing

@Xyne thank you for your great work. I used to use abyss to serve data file, but your tool is perfect smile


====* -- Joke
    O
    \|/ --- Me
    / \             Whooooosh

Offline

#41 2010-01-13 19:32:12

DarkVenger
Member
Registered: 2008-11-24
Posts: 35

Re: quickserve - easy ad-hoc file sharing

I used the already mentioned - woof - to simple share stuff in my LAN. But now quickserve surpassed it due to folder sharing and authorization. Thanks a lot Xyne!

Offline

#42 2010-01-13 22:39:41

UnDisbeliever
Member
From: Australia
Registered: 2009-08-07
Posts: 3

Re: quickserve - easy ad-hoc file sharing

I've been using ArchLinux for a while now and it's about time I get into the whole community of it all.

Xyne, I don't know how this sounds (I've kinda been awake too long), but I had this nagging feeling that something was missing from your script. So in the spirit of late morning coffee binges, I toyed with it and fixed two bugs that I noticed; (allow() was using options instead of the global variables; and that nothing was shared there are no command line options).

These updates add two new options that I think would be appricated;
-r which generates a random username and password, allowing for increased psuedo-security. And
-d displays the URL of the quickserv server to the screen. This url includes the authentication data, and I have found it useful when sharing the URL over IM (especially when combining it with -r).

Quick preview of the new features look like thus;

undisbeliever@deadlocked ~/src $ ./quickserve -rd
Username: NoxXGUnD
Password: WzDewkZy
http://NoxXGUnD:WzDewkZy@deadlocked:8080/
started httpserver on :8080...

Take the changes, or leave your code as-is. I was mainly doing this to gain experience in going through and working with someone elses code (something they don't really teach you at univeristy, along with proper coding semantics).

#!/usr/bin/env python

# Copyright (C) 2009  Xyne
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

# METADATA
# Version: 2.4.2

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from hashlib import md5
from mimetypes import guess_type
import os.path
from optparse import OptionParser
from time import gmtime,strftime
from urllib import unquote
from socket import gethostname
import string
import random

class MyHandler(BaseHTTPRequestHandler):

  def allow(self):
    global username, password
    if username and password:
      if 'Authorization' in self.headers and self.headers['Authorization'][:7] == 'Digest ':
        #client_username = None
        client_response = None
        #realm = None
        nonce = None
        for field in self.headers['Authorization'][7:].split(', '):
          #if field[:10] == 'username="':
          #  client_username = field[10:-1].replace('\"', '"')
          #el
          if field[:10] == 'response="':
            client_response = field[10:-1]
          #elif field[:7] == 'realm="':
          #  realm = field[7:-1]
          elif field[:7] == 'nonce="':
            nonce = field[7:-1]
        if client_response != None and nonce != None:
          m = md5()
          m.update(username + ':' + self.address_string() + ':' + password)
          ha1 = m.hexdigest()
          m = md5()
          m.update('GET:' + self.path)
          ha2 = m.hexdigest()
          m = md5()
          m.update(ha1 + ':' + nonce + ':' + ha2)
          response = m.hexdigest()
          if response == client_response:
            return True
      return False
    elif not username and not password:
      return True
    else:
      return False
      

  def do_GET(self):
    if not self.allow():
      self.send_response(401)
      self.send_header('WWW-Authenticate', 'Digest realm="' + self.address_string() + '"')
      self.send_header('Connection', 'close')
      self.end_headers()
      return

    global paths

    if self.path == '/':
      self.send_response(200)
      self.send_header('Content-type', 'text/html; charset=UTF-8')
      self.end_headers()
      html = get_html(self.path, sorted(paths.keys()))
      self.wfile.write( safe_encode_utf8(html) )
      return
    else:
      splitpath = self.path[1:].split(os.sep,1)
      if splitpath[0] in paths:
        if splitpath[0] == self.path[1:]:
          fpath = paths[splitpath[0]]
        elif len(splitpath) == 2:
          fpath = os.path.join(paths[splitpath[0]], splitpath[1])
        else:
          fpath = None
        if fpath:
          fpath = unquote(fpath)
        if os.path.isfile(fpath):
          self.transfer_file(fpath)
          return
        elif os.path.isdir(fpath):
          dirs, files = get_dirs_and_files(fpath)
          html = get_html(self.path, dirs + files)
          self.send_response(200)
          self.send_header('Content-type', 'text/html; charset=UTF-8')
          self.end_headers()
          self.wfile.write( safe_encode_utf8(html) )
          return
            
    self.send_response(404)
    self.send_header('Connection', 'close')
    self.end_headers()


  def do_POST(self):
    self.send_response(403)
    self.send_header('Connection', 'close')
    self.end_headers()
  
  
  def transfer_file(self,fpath):
    self.send_response(200)
    size = os.path.getsize(fpath)
    range_start = 0
    range_end = size - 1
    mimetype = guess_type(fpath)
    if not mimetype:
      mimetype = 'application/octet-stream'
    self.send_header('Accept-Ranges', 'bytes')
    self.send_header('Content-Type', mimetype)

    if 'range' in self.headers:
      s, e = self.headers['range'][6:].split('-', 1)
      if len(s) > 0:
        range_start = int(s)
      if len(e) > 0:
        range_end = int(e)

    self.send_header('Content-Range', 'bytes ' + str(range_start) + '-' + str(range_end) + '/' + str(size))
    self.send_header('Content-Length', range_end - range_start + 1)
    self.end_headers()

    f = open(fpath, 'rb')
    f.seek(range_start, 0)
    step = 4096
    total = 0
    while step > 0:
      if range_start + step > range_end + 1:
        step = range_end - range_start + 1
      try:
        self.wfile.write(f.read(step))
      except:
        break
      total += step
      range_start += step
    f.close()


def safe_encode_utf8(text):
  try:
    return text.encode('utf-8')
  except UnicodeDecodeError:
    return text

def get_dirs_and_files(path):
  if os.path.isdir(path):
    paths = os.listdir(path)
    return sorted(filter(lambda x: os.path.isdir(os.path.join(path,x)), paths)), sorted(filter(lambda x: os.path.isfile(os.path.join(path,x)), paths))
  elif os.path.isfile(path):
    return [], [os.path.basename(path)]
  else:
    return [], []



def get_html(path,contents):
  global paths
  path = unquote(path)
  i = path.find('/',1)
  if i > 0:
    root = path[1:i]
  else:
    root = path[1:]
  if root != '':
    backlink = '<a href="%s">[Back]</a>' % ('/' + path[1:].rpartition('/')[0])
  else:
    backlink = ''
  
  filelist_html = "<table>\n<tr><th>File</th><th>Size</th><th>Last Modified (GMT)</th></tr>\n"
  for c in contents:
    if root != '':
      upath = path.replace(root, paths[root]) + '/' + c
      href = path + '/' + c
    else:
      upath = paths[c]
      href = '/' + c
      
    stat = os.stat(upath)
    gm_time = gmtime(stat.st_mtime)
    str_time = strftime("%Y-%m-%d %H:%M:%S", gm_time)
    if os.path.isdir(upath):
      c += '/'
      size = ''
    else:
      size = format_size(stat.st_size)
    
    filelist_html += '<tr><td><a href="' + href + '">' + c + '</a></td><td class="alignr">' + size + '</td><td>' + str_time + "</td></tr>\n"
  filelist_html += "</table>\n"

  html = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>%(title)s - Quickserve</title>
  <style type="text/css">
      html, body { background-color: #fff;padding: 0;margin: 0 }
      body { font-family: "Lucida Grande", "Lucida Sans Unicode",
                          "Lucida Sans", Verdana, Arial, sans-serif }
      #wrapper { margin: 0 auto;width: 90%% }
      h1 { font-weight: normal; color: #333; margin-bottom: 0.5em;
           font-size: 2.5em; line-height: 1em }
      h1 a { font-size: 0.5em; text-decoration: none; margin-left: 1em; }
      table { font-family: monospace; border-spacing:10px 4px; margin-bottom: 5em }
      th { text-align: left }
      .alignr { text-align: right }
  </style>
</head>

<div id="wrapper">
<h1>%(title)s%(backlink)s</h1>
%(filelist)s
</div>

</body>
''' % {'title': unquote(path), 'filelist': filelist_html, 'backlink': backlink}

  return html



def format_size(size):
  s = ' B'
  if size > 1000:
    size /= 1000.0
    s = 'kB'
  if size > 1000:
    size /= 1000.0
    s = 'MB'
  if size > 1000:
    size /= 1000.0
    s = 'GB'
  if size > 1000:
    size /= 1000.0
    s = 'TB'
  return "%.02f %s" % (size,s)


def create_random_password(chars=string.ascii_letters, len=8):
  global username, password
  username = "".join(random.choice(chars) for x in range(len))
  password = "".join(random.choice(chars) for x in range(len))

  print 'Username:', username
  print 'Password:', password

def server_url(address=None, port=8080):
  global username, password
  if address is None or address is '':
      address = gethostname()
  if not username and not password:
    return 'http://%s:%d/' % (address, port)
  else:
    return 'http://%s:%s@%s:%d/' % (username, password, address, port)


def main(address='localhost', port=8080):
  try:
    server = HTTPServer((address, port), MyHandler)
    print 'started httpserver on %s:%d...' % (address, port)
    server.serve_forever()
  except KeyboardInterrupt:
    print '^C received, shutting down server'
    server.socket.close()



if __name__ == '__main__':
  myname = 'quickserve'
  parser = OptionParser(description=myname + ' - a simple HTTP server for quickly sharing files', usage=myname + ' [options] [paths]')
  parser.add_option("-b", "--bind", dest="address", default='', action="store",
                    help='Bind the server to this address. By default the server will listen on all interfaces.')
  parser.add_option("-p", "--port", dest="port", default=8080, type="int", action="store",
                    help='Set the server port (default: 8080)')
  parser.add_option("-u", "--username", dest="username", action="store",
                    help='Set authentication username.')
  parser.add_option("--password", dest="password", action="store",
                    help='Set authentication password.')
  parser.add_option("-r", "--random", dest="random_password", default=False, action="store_true",
                    help='Use a randomly generated authentication username and password. Overrides --username and --password.')
  parser.add_option("-d", "--display-url", dest="display_url", default=False, action="store_true",
                    help='Displays the URL of the web server (including authentication). Useful for when commuicating over IM.')
  (options, args) = parser.parse_args()
    
  global paths, username, password
  username = options.username
  password = options.password

  if options.random_password :
    create_random_password()
 
  if options.display_url :
    print server_url(options.address, options.port) 

  paths = {}
  for a in args:
    a = os.path.abspath(a)
    paths[os.path.basename(a)] = a
  if len(paths) == 0:
    a = os.getcwd()
    paths[os.path.basename(a)] = a

  main(options.address, options.port)

Army; as for the file uploading idea, there is a python script that could be modified to do this (http://fragments.turtlemeat.com/pythonwebserver.php). I've had some experience using python to create a HTTP_POST dummy server. I could probably add this option to quickserv if Xyne doesn't mind.


EDIT: I forgot to give you my thanks for creating this script. I've used it quite a few times in the last weekend and it working wondeerfully for my needs.

Last edited by UnDisbeliever (2010-01-13 22:48:37)

Offline

#43 2010-01-14 16:37:27

moose jaw
Member
From: Milwaukee
Registered: 2007-08-20
Posts: 98

Re: quickserve - easy ad-hoc file sharing

To add to the chorus of thanks: I just discovered quickserve and it's wonderful. Thanks!!!

Offline

#44 2010-01-16 08:07:07

Ape
Member
From: Finland
Registered: 2009-10-15
Posts: 46
Website

Re: quickserve - easy ad-hoc file sharing

I'd like to have it share the current folder when quickserve is ran without path parameters.

Offline

#45 2010-01-16 09:29:59

Xyne
Moderator/TU
Registered: 2008-08-03
Posts: 6,380
Website

Re: quickserve - easy ad-hoc file sharing

Ape wrote:

I'd like to have it share the current folder when quickserve is ran without path parameters.

So you want to be able to do

quickserve

because

 quickserve .

is too much to type?


My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

#46 2010-01-16 09:43:46

Ape
Member
From: Finland
Registered: 2009-10-15
Posts: 46
Website

Re: quickserve - easy ad-hoc file sharing

Xyne wrote:
Ape wrote:

I'd like to have it share the current folder when quickserve is ran without path parameters.

So you want to be able to do

quickserve

because

 quickserve .

is too much to type?

You are absolutely right there.

Offline

#47 2010-01-16 10:10:40

Xyne
Moderator/TU
Registered: 2008-08-03
Posts: 6,380
Website

Re: quickserve - easy ad-hoc file sharing

I'm reluctant to do that because it poses a slight security risk as it makes it easier to accidentally share a directory, which is potentially dangerous. It also adds a few lines to the code, all just to save 2 characters of typing which could easily be aliased in your .bashrc (alias quickserve="/usr/bin/quickserve .").

Sorry, but I don't think I'll implement that.


My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

#48 2010-01-16 10:22:34

Ape
Member
From: Finland
Registered: 2009-10-15
Posts: 46
Website

Re: quickserve - easy ad-hoc file sharing

Xyne wrote:

Sorry, but I don't think I'll implement that.

Well I understand your point, but this was the command I tried first. I somehow thought that it would serve the current folder. Currently it outputs this:

$ quickserve 
started httpserver on :8080...

Maybe you should make it more informative and say something like this:

$ quickserve 
usage: quickserve [path for sharing]

Also when I start the command with folder share and add or remove the files within, quickserve doesn't see the changes.

Offline

#49 2010-01-16 10:48:38

Xyne
Moderator/TU
Registered: 2008-08-03
Posts: 6,380
Website

Re: quickserve - easy ad-hoc file sharing

Ok, it now prints out the help message and exits when run without any paths. It also lists what it's serving when started.


My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

#50 2010-01-16 11:22:28

toad
Member
From: if only I knew
Registered: 2008-12-22
Posts: 1,775
Website

Re: quickserve - easy ad-hoc file sharing

toad@deskarch 981\12 ~ > quickserve
Traceback (most recent call last):
  File "/usr/bin/quickserve", line 293, in <module>
    main(options.address, options.port)
  File "/usr/bin/quickserve", line 263, in main
    server = HTTPServer((address, port), MyHandler)
  File "/usr/lib/python2.6/SocketServer.py", line 400, in __init__
    self.server_bind()
  File "/usr/lib/python2.6/BaseHTTPServer.py", line 108, in server_bind
    SocketServer.TCPServer.server_bind(self)
  File "/usr/lib/python2.6/SocketServer.py", line 411, in server_bind
    self.socket.bind(self.server_address)
  File "<string>", line 1, in bind
socket.error: [Errno 98] Address already in use

??

I then tried to upgrade:

  -> Downloading quickserve-2.5.tar.gz...
--2010-01-16 12:20:37--  http://xyne.archlinux.ca/src/quickserve-2.5.tar.gz
Resolving xyne.archlinux.ca... 69.89.25.172
Connecting to xyne.archlinux.ca|69.89.25.172|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10102 (9.9K) [application/x-gzip]
Saving to: `quickserve-2.5.tar.gz.part'

100%[=========================================================================================================================>] 10,102      25.1K/s   in 0.4s

2010-01-16 12:20:38 (25.1 KB/s) - `quickserve-2.5.tar.gz.part' saved [10102/10102]

==> Validating source files with md5sums...
    quickserve-2.5.tar.gz ... FAILED
==> ERROR: One or more files did not pass the validity check!
Error: Makepkg was unable to build quickserve package.

Error: unable to update quickserve

 Following packages have not been installed:
quickserve

toad@deskarch 982\14 ~ >

Is it just me or something else?


never trust a toad...
::Grateful ArchDonor::
::Grateful Wikipedia Donor::

Offline

Board footer

Powered by FluxBB