Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F35010690
woof-02.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
9 KB
Referenced Files
None
Subscribers
None
woof-02.py
View Options
#!/usr/bin/env python
#
# woof -- an ad-hoc single file webserver
# Copyright (C) 2004 Simon Budig <simon@budig.de>
#
# 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.
#
# A copy of the GNU General Public License is available at
# http://www.fsf.org/licenses/gpl.txt, you can also write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
import
sys
,
os
,
popen2
,
signal
,
select
,
socket
,
getopt
,
commands
import
urllib
,
BaseHTTPServer
,
SimpleHTTPServer
import
ConfigParser
maxdownloads
=
1
cpid
=
-
1
compressed
=
True
# Utility function to guess the IP (as a string) where the server can be
# reached from the outside. Quite nasty problem actually.
def
find_ip
():
os
.
environ
[
"PATH"
]
=
"/sbin:/usr/sbin:/usr/local/sbin:"
+
os
.
environ
[
"PATH"
]
platform
=
os
.
uname
()[
0
];
if
platform
==
"Linux"
:
netstat
=
commands
.
getoutput
(
"LC_MESSAGES=C netstat -rn"
)
defiface
=
[
i
.
split
()[
-
1
]
for
i
in
netstat
.
split
(
'
\n
'
)
if
i
.
split
()[
0
]
==
"0.0.0.0"
]
elif
platform
==
"Darwin"
:
netstat
=
commands
.
getoutput
(
"LC_MESSAGES=C netstat -rn"
)
defiface
=
[
i
.
split
()[
-
1
]
for
i
in
netstat
.
split
(
'
\n
'
)
if
len
(
i
)
>
2
and
i
.
split
()[
0
]
==
"default"
]
else
:
print
>>
sys
.
stderr
,
"Unsupported platform; please add support for your platform in find_ip()."
;
return
None
if
not
defiface
:
return
None
if
platform
==
"Linux"
:
ifcfg
=
commands
.
getoutput
(
"LC_MESSAGES=C ifconfig "
+
defiface
[
0
])
.
split
(
"inet addr:"
)
elif
platform
==
"Darwin"
:
ifcfg
=
commands
.
getoutput
(
"LC_MESSAGES=C ifconfig "
+
defiface
[
0
])
.
split
(
"inet "
)
if
len
(
ifcfg
)
!=
2
:
return
None
ip_addr
=
ifcfg
[
1
]
.
split
()[
0
]
# sanity check
try
:
ints
=
[
i
for
i
in
ip_addr
.
split
(
"."
)
if
0
<=
int
(
i
)
<=
255
]
if
len
(
ints
)
!=
4
:
return
None
except
ValueError
:
return
None
return
ip_addr
# Main class implementing an HTTP-Requesthandler, that serves just a single
# file and redirects all other requests to this file (this passes the actual
# filename to the client).
# Currently it is impossible to serve different files with different
# instances of this class.
class
FileServHTTPRequestHandler
(
BaseHTTPServer
.
BaseHTTPRequestHandler
):
server_version
=
"Simons FileServer"
protocol_version
=
"HTTP/1.0"
filename
=
"."
def
log_request
(
self
,
code
=
'-'
,
size
=
'-'
):
if
code
==
200
:
BaseHTTPServer
.
BaseHTTPRequestHandler
.
log_request
(
self
,
code
,
size
)
def
do_GET
(
self
):
global
maxdownloads
,
cpid
,
compressed
# Redirect any request to the filename of the file to serve.
# This hands over the filename to the client.
self
.
path
=
urllib
.
quote
(
urllib
.
unquote
(
self
.
path
))
location
=
"/"
+
urllib
.
quote
(
os
.
path
.
basename
(
self
.
filename
))
if
os
.
path
.
isdir
(
self
.
filename
):
if
compressed
:
location
+=
".tar.gz"
else
:
location
+=
".tar"
if
self
.
path
!=
location
:
txt
=
"""\
<html>
<head><title>302 Found</title></head>
<body>302 Found <a href="%s">here</a>.</body>
</html>\n"""
%
location
self
.
send_response
(
302
)
self
.
send_header
(
"Location"
,
location
)
self
.
send_header
(
"Content-type"
,
"text/html"
)
self
.
send_header
(
"Content-Length"
,
str
(
len
(
txt
)))
self
.
end_headers
()
self
.
wfile
.
write
(
txt
)
return
maxdownloads
-=
1
# let a separate process handle the actual download, so that
# multiple downloads can happen simultaneously.
cpid
=
os
.
fork
()
os
.
setpgrp
()
if
cpid
==
0
:
# Child process
size
=
-
1
datafile
=
None
child
=
None
if
os
.
path
.
isfile
(
self
.
filename
):
size
=
os
.
path
.
getsize
(
self
.
filename
)
datafile
=
open
(
self
.
filename
)
elif
os
.
path
.
isdir
(
self
.
filename
):
os
.
environ
[
'woof_dir'
],
os
.
environ
[
'woof_file'
]
=
os
.
path
.
split
(
self
.
filename
)
if
compressed
:
arg
=
'z'
else
:
arg
=
''
child
=
popen2
.
Popen3
(
'cd "$woof_dir";tar c
%s
f - "$woof_file"'
%
arg
)
datafile
=
child
.
fromchild
self
.
send_response
(
200
)
self
.
send_header
(
"Content-type"
,
"application/octet-stream"
)
if
size
>=
0
:
self
.
send_header
(
"Content-Length"
,
size
)
self
.
end_headers
()
try
:
try
:
while
1
:
if
select
.
select
([
datafile
],
[],
[],
2
)[
0
]:
c
=
datafile
.
read
(
1024
)
if
c
:
self
.
wfile
.
write
(
c
)
else
:
datafile
.
close
()
break
except
:
print
>>
sys
.
stderr
,
"Connection broke. Aborting"
finally
:
# for some reason tar doesnt stop working when the pipe breaks
if
child
:
if
child
.
poll
():
os
.
killpg
(
os
.
getpgid
(
child
.
pid
),
signal
.
SIGTERM
)
def
serve_files
(
filename
,
maxdown
=
1
,
ip_addr
=
''
,
port
=
8080
):
global
maxdownloads
maxdownloads
=
maxdown
# We have to somehow push the filename of the file to serve to the
# class handling the requests. This is an evil way to do this...
FileServHTTPRequestHandler
.
filename
=
filename
try
:
httpd
=
BaseHTTPServer
.
HTTPServer
((
ip_addr
,
port
),
FileServHTTPRequestHandler
)
except
socket
.
error
:
print
>>
sys
.
stderr
,
"cannot bind to IP address '
%s
' port
%d
"
%
(
ip_addr
,
port
)
sys
.
exit
(
1
)
if
not
ip_addr
:
ip_addr
=
find_ip
()
if
ip_addr
:
print
"Now serving on http://
%s
:
%s
/"
%
(
ip_addr
,
httpd
.
server_port
)
while
cpid
!=
0
and
maxdownloads
>
0
:
httpd
.
handle_request
()
def
usage
(
defport
,
defmaxdown
,
errmsg
=
None
):
name
=
os
.
path
.
basename
(
sys
.
argv
[
0
])
print
>>
sys
.
stderr
,
"""
Usage: %s [-i <ip_addr>] [-p <port>] [-c <count>] [-u] <file/dir>
%s [-i <ip_addr>] [-p <port>] [-c <count>] [-u] -s
Serves a single file <count> times via http on port <port> on IP
address <ip_addr>.
When a directory is specified, a .tar.gz archive gets served (or an
uncompressed tar archive when -u is specified), when -s is specified
instead of a filename, %s distributes itself.
defaults: count = %d, port = %d
You can specify different defaults in two locations: /etc/woofrc
and ~/.woofrc can be INI-style config files containing the default
port and the default count. The file in the home directory takes
precedence.
Sample file:
[main]
port = 8008
count = 2
"""
%
(
name
,
name
,
name
,
defmaxdown
,
defport
)
if
errmsg
:
print
>>
sys
.
stderr
,
errmsg
print
>>
sys
.
stderr
sys
.
exit
(
1
)
def
main
():
global
cpid
,
compressed
maxdown
=
1
port
=
8080
ip_addr
=
''
config
=
ConfigParser
.
ConfigParser
()
config
.
read
([
'/etc/woofrc'
,
os
.
path
.
expanduser
(
'~/.woofrc'
)])
if
config
.
has_option
(
'main'
,
'port'
):
port
=
config
.
getint
(
'main'
,
'port'
)
if
config
.
has_option
(
'main'
,
'count'
):
maxdown
=
config
.
getint
(
'main'
,
'count'
)
if
config
.
has_option
(
'main'
,
'ip'
):
maxdown
=
config
.
get
(
'main'
,
'ip'
)
if
config
.
has_option
(
'main'
,
'compressed'
):
compressed
=
config
.
getboolean
(
'main'
,
'compressed'
)
defaultport
=
port
defaultmaxdown
=
maxdown
try
:
options
,
filenames
=
getopt
.
getopt
(
sys
.
argv
[
1
:],
"hsui:c:p:"
)
except
getopt
.
GetoptError
,
desc
:
usage
(
defaultport
,
defaultmaxdown
,
desc
)
for
option
,
val
in
options
:
if
option
==
'-c'
:
try
:
maxdown
=
int
(
val
)
if
maxdown
<=
0
:
raise
ValueError
except
ValueError
:
usage
(
defaultport
,
defaultmaxdown
,
"invalid download count:
%r
. "
"Please specify an integer >= 0."
%
val
)
elif
option
==
'-i'
:
ip_addr
=
val
elif
option
==
'-p'
:
try
:
port
=
int
(
val
)
except
ValueError
:
usage
(
defaultport
,
defaultmaxdown
,
"invalid port number:
%r
. Please specify an integer"
%
val
)
elif
option
==
'-s'
:
filenames
.
append
(
__file__
)
elif
option
==
'-h'
:
usage
(
defaultport
,
defaultmaxdown
)
elif
option
==
'-u'
:
compressed
=
False
else
:
usage
(
defaultport
,
defaultmaxdown
,
"Unknown option:
%r
"
%
option
)
if
len
(
filenames
)
==
1
:
filename
=
os
.
path
.
abspath
(
filenames
[
0
])
else
:
usage
(
defaultport
,
defaultmaxdown
,
"Can only serve single files/directories."
)
if
not
os
.
path
.
exists
(
filename
):
usage
(
defaultport
,
defaultmaxdown
,
"
%s
: No such file or directory"
%
filenames
[
0
])
if
not
(
os
.
path
.
isfile
(
filename
)
or
os
.
path
.
isdir
(
filename
)):
usage
(
defaultport
,
defaultmaxdown
,
"
%s
: Neither file nor directory"
%
filenames
[
0
])
serve_files
(
filename
,
maxdown
,
ip_addr
,
port
)
# wait for child processes to terminate
if
cpid
!=
0
:
try
:
while
1
:
os
.
wait
()
except
OSError
:
pass
if
__name__
==
'__main__'
:
try
:
main
()
except
KeyboardInterrupt
:
pass
File Metadata
Details
Attached
Mime Type
text/x-python
Expires
Tue, Jul 7, 23:34 (2 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3876536
Default Alt Text
woof-02.py (9 KB)
Attached To
Mode
rWURF wurf
Attached
Detach File
Event Timeline
Log In to Comment