Skip to content

Commit e966411

Browse files
committed
httpserve: handle dangling symlinks & show listening ip addresses
1 parent 50498a4 commit e966411

File tree

1 file changed

+56
-9
lines changed

1 file changed

+56
-9
lines changed

bin/httpserve

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import os
2020
import posixpath
2121
import re
2222
import shutil
23+
import socket
2324
import socketserver
25+
import subprocess
2426
import sys
2527
import time
2628
import urllib.error
@@ -218,8 +220,7 @@ class SimpleHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
218220
f.write(b"<html>\n")
219221
f.write(
220222
(
221-
'<meta http-equiv="Content-Type" '
222-
'content="text/html; charset=%s">' % enc
223+
'<meta http-equiv="Content-Type" content="text/html; charset=%s">' % enc
223224
).encode(enc)
224225
)
225226
f.write(("<title>Directory listing for %s</title>\n" % displaypath).encode(enc))
@@ -257,8 +258,15 @@ class SimpleHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
257258
dirimage = "data:image/gif;base64,R0lGODlhGAAYAMIAAP///7+/v7u7u1ZWVTc3NwAAAAAAAAAAACH+RFRoaXMgaWNvbiBpcyBpbiB0aGUgcHVibGljIGRvbWFpbi4gMTk5NSBLZXZpbiBIdWdoZXMsIGtldmluaEBlaXQuY29tACH5BAEAAAEALAAAAAAYABgAAANdGLrc/jAuQaulQwYBuv9cFnFfSYoPWXoq2qgrALsTYN+4QOg6veFAG2FIdMCCNgvBiAxWlq8mUseUBqGMoxWArW1xXYXWGv59b+WxNH1GV9vsNvd9jsMhxLw+70gAADs="
258259
fullname = os.path.join(path, name)
259260
displayname = linkname = name
260-
fsize = fbytes(os.path.getsize(fullname))
261-
created_date = time.ctime(os.path.getctime(fullname))
261+
262+
try:
263+
fsize = fbytes(os.path.getsize(fullname))
264+
created_date = time.ctime(os.path.getctime(fullname))
265+
except (FileNotFoundError, OSError):
266+
# Handle dangling symlinks and other file access errors
267+
fsize = "?"
268+
created_date = "?"
269+
262270
# Append / for directories or @ for symbolic links
263271
if os.path.isdir(fullname):
264272
dirimage = "data:image/png;base64,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"
@@ -372,7 +380,7 @@ parser.add_argument(
372380
"-b",
373381
default="",
374382
metavar="ADDRESS",
375-
help="Specify alternate bind address " "[default: all interfaces]",
383+
help="Specify alternate bind address [default: all interfaces]",
376384
)
377385
parser.add_argument(
378386
"port",
@@ -388,14 +396,53 @@ PORT = args.port
388396
BIND = args.bind
389397
HOST = BIND
390398

391-
if HOST == "":
392-
HOST = "localhost"
399+
400+
def get_ip_addresses():
401+
"""Get all IPv4 addresses for this host."""
402+
addresses = []
403+
404+
try:
405+
# Try ip addr first (modern systems)
406+
output = subprocess.check_output(["ip", "addr"], text=True)
407+
for line in output.split("\n"):
408+
if "inet " in line and "scope global" in line:
409+
ip = line.split()[1].split("/")[0]
410+
addresses.append(ip)
411+
except (subprocess.CalledProcessError, FileNotFoundError):
412+
try:
413+
# Fall back to ifconfig
414+
output = subprocess.check_output(["ifconfig"], text=True)
415+
for line in output.split("\n"):
416+
if "inet " in line and "broadcast" in line:
417+
ip = line.split()[1]
418+
addresses.append(ip)
419+
except (subprocess.CalledProcessError, FileNotFoundError):
420+
# If both fail, just use socket to get hostname IP
421+
try:
422+
hostname_ip = socket.gethostbyname(socket.gethostname())
423+
if hostname_ip != "127.0.0.1":
424+
addresses.append(hostname_ip)
425+
except socket.gaierror:
426+
pass
427+
428+
# Always include localhost
429+
if "127.0.0.1" not in addresses:
430+
addresses.append("127.0.0.1")
431+
432+
return sorted(addresses) # Sort for consistent output
433+
434+
435+
if HOST in ("", "0.0.0.0"):
436+
HOST = "0.0.0.0" # Listen on all interfaces
437+
print("Server accessible at:")
438+
for addr in get_ip_addresses():
439+
print(f" http://{addr}:{PORT}/")
440+
else:
441+
print(f"Server accessible at: http://{HOST}:{PORT}/")
393442

394443
Handler = SimpleHTTPRequestHandler
395444

396445
with socketserver.TCPServer((BIND, PORT), Handler) as httpd:
397-
serve_message = "Serving HTTP on {host} port {port} (http://{host}:{port}/) ..."
398-
print(serve_message.format(host=HOST, port=PORT))
399446
try:
400447
httpd.serve_forever()
401448
except KeyboardInterrupt:

0 commit comments

Comments
 (0)