add code
This commit is contained in:
parent
fb02534cd4
commit
4c1915a2d3
201
index.html
Normal file
201
index.html
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background-color: #e2e2e2;
|
||||||
|
}
|
||||||
|
.subfolders {
|
||||||
|
display: flex;
|
||||||
|
background-color: #e2e2e2;
|
||||||
|
padding: 1.0rem;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
border-bottom: solid;
|
||||||
|
border-bottom-width: 2.0px;
|
||||||
|
border-bottom-color: #c0c0c0;
|
||||||
|
}
|
||||||
|
.subfolders > a {
|
||||||
|
margin: 0.5rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #2e2e22;
|
||||||
|
font-size: large;
|
||||||
|
background-color: #ffffff;
|
||||||
|
outline-color: #202020;
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
padding: 1.0rem;
|
||||||
|
box-shadow: 0 0 0.5rem 0.5rem #e1e1e1;
|
||||||
|
}
|
||||||
|
.subfolders > a:hover {
|
||||||
|
background-color: #2e2e22;
|
||||||
|
color: #e2e2e2;
|
||||||
|
}
|
||||||
|
.images {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 1.0rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.imgcontainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 0.3rem;
|
||||||
|
padding: 0.3rem;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.imgcontainer > a {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.imgcontainer > p {
|
||||||
|
text-align: center;
|
||||||
|
margin: 0.2rem;
|
||||||
|
}
|
||||||
|
.more {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #2e2e2e;
|
||||||
|
color: #e2e2e2;
|
||||||
|
font-size: x-large;
|
||||||
|
padding: 1.0rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>ImageServer</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="subfolders" id="subfolders">
|
||||||
|
<!-- <a href="test">..[Parent Dir]</a> -->
|
||||||
|
</div>
|
||||||
|
<div class="images" id="images">
|
||||||
|
<!-- <div class="imgcontainer"><img src="torch_tf.png" height="400px"><p>test1.png</p></div> -->
|
||||||
|
</div>
|
||||||
|
<div class="more" onclick="show_more_image()">
|
||||||
|
加载更多
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function parse_url(url) {
|
||||||
|
if (url == '') {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
urls = url.substr(1).split('&')
|
||||||
|
params = {}
|
||||||
|
for (var item of urls) {
|
||||||
|
delemeter_pos = item.indexOf('=')
|
||||||
|
key = null, value = null
|
||||||
|
if (delemeter_pos == -1) {
|
||||||
|
key = item
|
||||||
|
} else {
|
||||||
|
key = item.substr(0, delemeter_pos)
|
||||||
|
value = item.substr(delemeter_pos + 1)
|
||||||
|
}
|
||||||
|
params[key] = value
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
function encode_url(params) {
|
||||||
|
url = []
|
||||||
|
for (var key in params) {
|
||||||
|
url.push(key + '=' + params[key])
|
||||||
|
}
|
||||||
|
return url.join('&')
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_directory(dirs, folder_node) {
|
||||||
|
folder_node.innerHTML = ''
|
||||||
|
image_node.innerHTML = ''
|
||||||
|
path = params['path']
|
||||||
|
path = path.split('/')
|
||||||
|
path = path.slice(0, path.length - 1).join('/')
|
||||||
|
this_params = JSON.parse(JSON.stringify(params))
|
||||||
|
this_params['path'] = path
|
||||||
|
this_node = document.createElement('a')
|
||||||
|
this_node.href = host + "/?" + encode_url(this_params)
|
||||||
|
this_node.innerHTML = '..[ParentDir]'
|
||||||
|
folder_node.appendChild(this_node)
|
||||||
|
dirs.forEach(element => {
|
||||||
|
this_node = document.createElement('a')
|
||||||
|
elem_split = element.split('/')
|
||||||
|
this_params = JSON.parse(JSON.stringify(params))
|
||||||
|
this_params['path'] = element
|
||||||
|
this_node.href = host + "/?" + encode_url(this_params)
|
||||||
|
this_node.innerHTML = elem_split[elem_split.length-1]
|
||||||
|
folder_node.appendChild(this_node)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function show_image(imgs, image_node, start, max) {
|
||||||
|
this_imgs = imgs.slice(start, start + max)
|
||||||
|
this_imgs.forEach(element => {
|
||||||
|
elem_split = element.split('/')
|
||||||
|
elem_name = elem_split[elem_split.length-1]
|
||||||
|
this_node = document.createElement('div')
|
||||||
|
this_node.className = 'imgcontainer'
|
||||||
|
img_url = host + `/img?path=${element}`
|
||||||
|
rawurl = img_url
|
||||||
|
size_attr = ''
|
||||||
|
if (params.hasOwnProperty('width')) {
|
||||||
|
width = params['width']
|
||||||
|
img_url += `&width=${width}`
|
||||||
|
size_attr += 'width=${width}px'
|
||||||
|
}
|
||||||
|
if (params.hasOwnProperty('height')) {
|
||||||
|
height = params['height']
|
||||||
|
img_url += `&height=${height}`
|
||||||
|
size_attr += `height=${height}px`
|
||||||
|
}
|
||||||
|
|
||||||
|
this_node.innerHTML = `<a href="${rawurl}" target="_blank"><img src="${img_url}" ${size_attr}"></a><p>${elem_name}</p>`
|
||||||
|
image_node.appendChild(this_node)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function show_more_image() {
|
||||||
|
start = parseInt(params['start'])
|
||||||
|
max = parseInt(params['max'])
|
||||||
|
params['start'] = (start + max).toString()
|
||||||
|
show_image(imgs, image_node, start, max)
|
||||||
|
}
|
||||||
|
|
||||||
|
folder_node = document.getElementById('subfolders')
|
||||||
|
image_node = document.getElementById('images')
|
||||||
|
var search = window.location.search
|
||||||
|
var host = window.location.protocol + '//' + window.location.host
|
||||||
|
params = parse_url(search)
|
||||||
|
var start = '0'
|
||||||
|
var max = '50'
|
||||||
|
if (!params.hasOwnProperty('start')){
|
||||||
|
params['start'] = start
|
||||||
|
}
|
||||||
|
if (!params.hasOwnProperty('max')) {
|
||||||
|
params['max'] = max
|
||||||
|
}
|
||||||
|
if (!params.hasOwnProperty('path')) {
|
||||||
|
if (!(params.hasOwnProperty('width') | params.hasOwnProperty())) {
|
||||||
|
params['height'] = '256'
|
||||||
|
}
|
||||||
|
params['path'] = '/'
|
||||||
|
encoded = encode_url(params)
|
||||||
|
window.location.search = encoded
|
||||||
|
}
|
||||||
|
document.title = 'IM: ' + params['path']
|
||||||
|
|
||||||
|
var http = new XMLHttpRequest()
|
||||||
|
http.open("GET", host + '/directory?path=' + params['path'])
|
||||||
|
http.send()
|
||||||
|
http.onloadend = (e) => {
|
||||||
|
response = JSON.parse(http.responseText)
|
||||||
|
dirs = response['dirs']
|
||||||
|
imgs = response['imgs']
|
||||||
|
show_directory(dirs, folder_node)
|
||||||
|
var start = parseInt(params['start'])
|
||||||
|
var max = parseInt(params['max'])
|
||||||
|
show_image(imgs, image_node, start, max)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
251
network.py
Normal file
251
network.py
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
import socket
|
||||||
|
import threading
|
||||||
|
import traceback
|
||||||
|
from http import HTTPStatus
|
||||||
|
|
||||||
|
def parse_address(address):
|
||||||
|
try:
|
||||||
|
ip = address.split(':')[0]
|
||||||
|
port = int(address.split(':')[1])
|
||||||
|
return ip, port
|
||||||
|
except:
|
||||||
|
print('Invalid address [{0}]').format(address)
|
||||||
|
print('exception information:')
|
||||||
|
print(traceback.format_exc())
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
class BasicTCPServer():
|
||||||
|
def __init__(self, address="127.0.0.1:12345", handler=None):
|
||||||
|
self.ip, self.port = parse_address(address)
|
||||||
|
|
||||||
|
self.handler = handler if handler is not None else lambda clientsocket, addr:None
|
||||||
|
|
||||||
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
self.socket.bind((self.ip, self.port))
|
||||||
|
self.socket.listen(5)
|
||||||
|
self.socket.settimeout(0.5)
|
||||||
|
self.terminate = False
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.stop()
|
||||||
|
|
||||||
|
def set_handler(self, handler):
|
||||||
|
self.handler = handler
|
||||||
|
|
||||||
|
def handle_message(self, clientsocket, addr):
|
||||||
|
self.handler(clientsocket, addr)
|
||||||
|
def loop(self):
|
||||||
|
try:
|
||||||
|
while not self.terminate:
|
||||||
|
try:
|
||||||
|
clientsocket,addr = self.socket.accept()
|
||||||
|
t = threading.Thread(
|
||||||
|
target=self.handle_message,
|
||||||
|
args=[clientsocket, addr],
|
||||||
|
name='Client[{0}]'.format(addr),
|
||||||
|
daemon=True
|
||||||
|
)
|
||||||
|
t.start()
|
||||||
|
except socket.timeout:
|
||||||
|
pass
|
||||||
|
except socket.timeout:
|
||||||
|
pass
|
||||||
|
except (Exception, KeyboardInterrupt):
|
||||||
|
self.socket.close()
|
||||||
|
print('Bye~')
|
||||||
|
|
||||||
|
def start(self, back=True):
|
||||||
|
if back:
|
||||||
|
t = threading.Thread(target=self.loop, name='SocketMainLoop', daemon=True)
|
||||||
|
t.start()
|
||||||
|
else:
|
||||||
|
self.loop()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.terminate = True
|
||||||
|
self.socket.close()
|
||||||
|
|
||||||
|
class HTTPBasicHeader():
|
||||||
|
def __init__(self, words=None, content=None):
|
||||||
|
if content is None:
|
||||||
|
content = {}
|
||||||
|
self.words = words
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
def encode(self):
|
||||||
|
contents = [' '.join([str(w) for w in self.words])]
|
||||||
|
contents += ['{0}: {1}'.format(name, value) for name, value in self.content.items()]
|
||||||
|
header_message = '\r\n'.join(contents)
|
||||||
|
header_message = header_message.encode('utf-8')
|
||||||
|
return header_message
|
||||||
|
|
||||||
|
def decode(self, message):
|
||||||
|
if type(message) is bytes:
|
||||||
|
message = message.decode('utf-8')
|
||||||
|
contents = message.split('\r\n')
|
||||||
|
contents = [line.strip() for line in contents]
|
||||||
|
contents = [line for line in contents if line != '']
|
||||||
|
header_line = contents[0]
|
||||||
|
contents = contents[1:]
|
||||||
|
words = header_line.split(' ')
|
||||||
|
valid_contents = {}
|
||||||
|
invalid_lines = []
|
||||||
|
for line in contents:
|
||||||
|
delpos = line.find(':')
|
||||||
|
if delpos == -1:
|
||||||
|
invalid_lines.append(line)
|
||||||
|
else:
|
||||||
|
key = line[:delpos].strip()
|
||||||
|
value = line[delpos+1:].strip()
|
||||||
|
valid_contents[key] = value
|
||||||
|
if len(invalid_lines) > 0:
|
||||||
|
print('Warning: in-completed line found:')
|
||||||
|
print(invalid_lines)
|
||||||
|
return words, valid_contents
|
||||||
|
|
||||||
|
class InvalidHTTPHeaderError(Exception):
|
||||||
|
def __init__(self, message=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class HTTPHeaderDictInterface():
|
||||||
|
def __init__(self, content):
|
||||||
|
self.content = content
|
||||||
|
def __getitem__(self, index):
|
||||||
|
return self.content[index]
|
||||||
|
def __setitem__(self, index, value):
|
||||||
|
self.content[index] = value
|
||||||
|
def __contains__(self, index):
|
||||||
|
return index in self.content
|
||||||
|
def __iter__(self, index):
|
||||||
|
for key in self.content:
|
||||||
|
yield key
|
||||||
|
|
||||||
|
class HTTPRequestHeader(HTTPHeaderDictInterface):
|
||||||
|
methods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH']
|
||||||
|
def __init__(self, method=None, url=None, version='HTTP/1.1', content=None):
|
||||||
|
if content is None:
|
||||||
|
content = {}
|
||||||
|
self.method = method
|
||||||
|
self.url = url
|
||||||
|
self.version = version
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
def check_valid(self):
|
||||||
|
if self.method is None or self.url is None:
|
||||||
|
return False
|
||||||
|
elif self.method not in HTTPRequestHeader.methods:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def encode(self):
|
||||||
|
if not self.check_valid():
|
||||||
|
raise InvalidHTTPHeaderError('Invalid header, method and url should at least be provided.')
|
||||||
|
words = [self.method, self.url, self.version]
|
||||||
|
content = self.content
|
||||||
|
message = HTTPBasicHeader(words=words, content=content).encode()
|
||||||
|
return message
|
||||||
|
def decode(self, message):
|
||||||
|
words, content = HTTPBasicHeader().decode(message)
|
||||||
|
if len(words) != 3:
|
||||||
|
raise InvalidHTTPHeaderError
|
||||||
|
self.method, self.url, self.version = words
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
class HTTPResponseHeader(HTTPHeaderDictInterface):
|
||||||
|
def __init__(self, code=None, version='HTTP/1.1', content=None):
|
||||||
|
if content is None:
|
||||||
|
content = {}
|
||||||
|
self.code = code
|
||||||
|
self.version = version
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
def check_valid(self):
|
||||||
|
if self.code is None:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def encode(self):
|
||||||
|
if not self.check_valid():
|
||||||
|
raise InvalidHTTPHeaderError('Invalid header, code is required for a http header.')
|
||||||
|
words = [self.version, self.code, HTTPStatus(self.code).phrase]
|
||||||
|
content = self.content
|
||||||
|
message = HTTPBasicHeader(words=words, content=content).encode()
|
||||||
|
return message
|
||||||
|
def decode(self, message):
|
||||||
|
words, content = HTTPBasicHeader().decode(message)
|
||||||
|
if len(words) != 3:
|
||||||
|
raise InvalidHTTPHeaderError
|
||||||
|
self.version, self.code, _ = words
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
class SingleHTTPConnection():
|
||||||
|
def __init__(self, header, cached, connection):
|
||||||
|
self.header = header
|
||||||
|
self.connection = connection # connection is a basic socket connection.
|
||||||
|
self.cached = cached
|
||||||
|
self.length = 0
|
||||||
|
if 'Content-Length' in self.header:
|
||||||
|
self.length = self.header['Content-Length'] # the remeaning legth of the connection.
|
||||||
|
|
||||||
|
# To ensure all data is send, so we use sendall here.
|
||||||
|
def write(self, message):
|
||||||
|
self.connection.sendall(message)
|
||||||
|
|
||||||
|
# this function will read fixed length from the socket.
|
||||||
|
def read_fixed_size(self, size):
|
||||||
|
if size <= 0:
|
||||||
|
return b''
|
||||||
|
recvd = b''
|
||||||
|
while len(recvd) < size:
|
||||||
|
this_message = self.connection.recv(size - len(recvd))
|
||||||
|
if len(this_message) == 0:
|
||||||
|
break
|
||||||
|
recvd += this_message
|
||||||
|
return recvd
|
||||||
|
|
||||||
|
def read(self, size=None):
|
||||||
|
if size is None:
|
||||||
|
self.length = 0
|
||||||
|
return self.cached + self.read_fixed_size(self.length - self.cached)
|
||||||
|
if size > self.length:
|
||||||
|
size = self.length
|
||||||
|
message = b''
|
||||||
|
message = self.cached[:size]
|
||||||
|
if len(message) < size:
|
||||||
|
message += self.read_fixed_size(size - len(message))
|
||||||
|
self.length -= size
|
||||||
|
return message
|
||||||
|
|
||||||
|
class HTTPBaseServer(BasicTCPServer):
|
||||||
|
def __init__(self, request_handler, bind_addr='127.0.0.1:80'):
|
||||||
|
if not callable(request_handler):
|
||||||
|
raise ValueError('You must provide an callable request handler.')
|
||||||
|
super(HTTPBaseServer, self).__init__(address=bind_addr)
|
||||||
|
self.request_handler = request_handler
|
||||||
|
|
||||||
|
def handle_message(self, sock, addr):
|
||||||
|
# print('processing connection from ', addr)
|
||||||
|
# recieve until header ends.
|
||||||
|
delemeter = b'\r\n\r\n'
|
||||||
|
header_text = b''
|
||||||
|
# print('New connection established from', addr)
|
||||||
|
while True:
|
||||||
|
# wait for the end of the
|
||||||
|
while header_text.find(delemeter) == -1:
|
||||||
|
this_mesage = sock.recv(8192)
|
||||||
|
if len(this_mesage) == 0:
|
||||||
|
# print('connection exited. addr:', addr)
|
||||||
|
return
|
||||||
|
header_text += this_mesage
|
||||||
|
delpos = header_text.find(delemeter)
|
||||||
|
content = header_text[delpos + len(delemeter):]
|
||||||
|
header_text = header_text[:delpos]
|
||||||
|
header = HTTPRequestHeader()
|
||||||
|
header.decode(header_text)
|
||||||
|
header_text = b''
|
||||||
|
wraped_connection = SingleHTTPConnection(header, content, sock)
|
||||||
|
self.request_handler(wraped_connection) # the request handler can only read limited data, once finish, send, and return, we will move on.
|
||||||
|
# print('request handler finished.')
|
||||||
219
server.py
Normal file
219
server.py
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
import os
|
||||||
|
import io
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
|
||||||
|
import threading
|
||||||
|
import queue
|
||||||
|
from http import HTTPStatus
|
||||||
|
from urllib.parse import unquote
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
from network import HTTPBaseServer, HTTPResponseHeader
|
||||||
|
|
||||||
|
app_dir = os.path.split(os.path.realpath(__file__))[0]
|
||||||
|
index_path = os.path.join(app_dir, 'index.html')
|
||||||
|
|
||||||
|
def loadfile(path):
|
||||||
|
with open(path, 'r', encoding='utf-8') as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
class HTTPImageServer():
|
||||||
|
def __init__(self, bind_addr, imgroot='.'):
|
||||||
|
self.server = HTTPBaseServer(request_handler=self.handle, bind_addr=bind_addr)
|
||||||
|
self.imgroot = imgroot
|
||||||
|
self.img_extension = ['png', 'jpg', 'jpeg', 'tiff', 'webp', 'bmp']
|
||||||
|
self.print_lock = threading.Lock()
|
||||||
|
self.logqueue = queue.Queue()
|
||||||
|
def start(self, back=True):
|
||||||
|
t = threading.Thread(target=self.logger, name='Logger thread', daemon=True)
|
||||||
|
t.start()
|
||||||
|
self.server.start(back=back)
|
||||||
|
|
||||||
|
|
||||||
|
def logger(self):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
msg = self.logqueue.get(timeout=1)
|
||||||
|
print(msg)
|
||||||
|
except queue.Empty:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_url(url):
|
||||||
|
location = url.split('?')[0]
|
||||||
|
params_str = url[len(location)+1:]
|
||||||
|
location = unquote(location)
|
||||||
|
params = {}
|
||||||
|
splits = params_str.split('&')
|
||||||
|
for split in splits:
|
||||||
|
split = unquote(split)
|
||||||
|
eq_pos = split.find('=')
|
||||||
|
if eq_pos == -1:
|
||||||
|
params[split] = None
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
key = split[:eq_pos]
|
||||||
|
value = split[eq_pos+1:]
|
||||||
|
params[key] = value
|
||||||
|
return location, params
|
||||||
|
|
||||||
|
def log(self, msg):
|
||||||
|
self.logqueue.put(msg)
|
||||||
|
|
||||||
|
def response(self, connection, header, content):
|
||||||
|
msg = '[{time}] {method}: {url} - {stat}'.format(
|
||||||
|
time = time.strftime("%H:%M:%S", time.localtime()),
|
||||||
|
method = connection.header.method,
|
||||||
|
url = connection.header.url,
|
||||||
|
stat = '{0}({1})'.format(header.code, HTTPStatus(header.code).phrase)
|
||||||
|
)
|
||||||
|
self.log(msg)
|
||||||
|
|
||||||
|
header['Content-Length'] = len(content)
|
||||||
|
connection.write(header.encode() + b'\r\n\r\n')
|
||||||
|
connection.write(content)
|
||||||
|
|
||||||
|
def response_404(self, connection):
|
||||||
|
header = HTTPResponseHeader(404)
|
||||||
|
content = b'404 Not Found'
|
||||||
|
self.response(connection, header, content)
|
||||||
|
@staticmethod
|
||||||
|
def safe_path(path):
|
||||||
|
path = '/'.join(path.split('\\'))
|
||||||
|
path = path.split('/')
|
||||||
|
path = [p for p in path if p not in ['', '..', '.']]
|
||||||
|
path = '/'.join(path)
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def handle_index(self, params):
|
||||||
|
if 'path' not in params:
|
||||||
|
return HTTPResponseHeader(404), b'404 Not Found'
|
||||||
|
directory = params['path']
|
||||||
|
while '\\' in directory:
|
||||||
|
directory = directory.replace('\\', '/')
|
||||||
|
directory = self.safe_path(directory)
|
||||||
|
disk_directory = os.path.join(self.imgroot, directory)
|
||||||
|
filenames = []
|
||||||
|
try:
|
||||||
|
filenames = os.listdir(disk_directory)
|
||||||
|
filenames.sort()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
response = {"dirs": [], "imgs": []}
|
||||||
|
for filename in filenames:
|
||||||
|
full_path = os.path.join(disk_directory, filename)
|
||||||
|
request_path = '/{0}/{1}'.format(directory, filename)
|
||||||
|
request_path = '/' + request_path.strip('/\\')
|
||||||
|
if os.path.isdir(full_path):
|
||||||
|
response['dirs'].append(request_path)
|
||||||
|
else:
|
||||||
|
if filename.split('.')[-1] in self.img_extension:
|
||||||
|
response['imgs'].append(request_path)
|
||||||
|
response = json.dumps(response).encode('utf-8')
|
||||||
|
return HTTPResponseHeader(200), response
|
||||||
|
|
||||||
|
def handle_image(self, params):
|
||||||
|
invalid_request = False
|
||||||
|
if 'path' not in params:
|
||||||
|
invalid_request = True
|
||||||
|
filepath = params['path']
|
||||||
|
filepath = self.safe_path(filepath)
|
||||||
|
full_path = os.path.join(self.imgroot, filepath)
|
||||||
|
if filepath.split('.')[-1] not in self.img_extension:
|
||||||
|
invalid_request = True
|
||||||
|
elif not os.path.isfile(full_path):
|
||||||
|
invalid_request = True
|
||||||
|
|
||||||
|
# parse height and width limit.
|
||||||
|
max_h, max_w = None, None
|
||||||
|
try:
|
||||||
|
if 'height' in params:
|
||||||
|
max_h = int(params['height'])
|
||||||
|
elif 'width' in params:
|
||||||
|
max_w = int(params['width'])
|
||||||
|
except Exception:
|
||||||
|
invalid_request = True
|
||||||
|
|
||||||
|
if invalid_request:
|
||||||
|
return HTTPResponseHeader(404), b'404 Not Found'
|
||||||
|
|
||||||
|
header = HTTPResponseHeader(200)
|
||||||
|
content = b''
|
||||||
|
if max_h is not None or max_w is not None:
|
||||||
|
img = Image.open(full_path)
|
||||||
|
real_w, real_h = img.size
|
||||||
|
h_ratio = None
|
||||||
|
w_ratio = None
|
||||||
|
if max_h is not None:
|
||||||
|
h_ratio = max_h / real_h
|
||||||
|
h_ratio = h_ratio if h_ratio < 1 else 1
|
||||||
|
if max_w is not None:
|
||||||
|
w_ratio = max_w / real_w
|
||||||
|
w_ratio = w_ratio if w_ratio < 1 else 1
|
||||||
|
max_ratio = 0
|
||||||
|
if h_ratio is None:
|
||||||
|
max_ratio = w_ratio
|
||||||
|
elif w_ratio is None:
|
||||||
|
max_ratio = h_ratio
|
||||||
|
else:
|
||||||
|
max_ratio = h_ratio if h_ratio < w_ratio else w_ratio
|
||||||
|
new_h, new_w = (real_h * max_ratio, real_w * max_ratio)
|
||||||
|
img = img.resize((int(new_w), int(new_h)))
|
||||||
|
img_stream = io.BytesIO()
|
||||||
|
img = img.save(img_stream, format='webp')
|
||||||
|
content = img_stream.getvalue()
|
||||||
|
else:
|
||||||
|
with open(full_path, 'rb') as f:
|
||||||
|
content = f.read()
|
||||||
|
return header, content
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
request_type:
|
||||||
|
request index: http://domain.com/directory?path=relative/path/to/file
|
||||||
|
request image: http://domain.com/img?path=relative/path/to/file&height=100px&width=200px
|
||||||
|
"""
|
||||||
|
def handle(self, connection):
|
||||||
|
method = connection.header.method
|
||||||
|
if method != 'GET':
|
||||||
|
self.response_404(connection)
|
||||||
|
return
|
||||||
|
|
||||||
|
url = connection.header.url
|
||||||
|
location, params = self.parse_url(url)
|
||||||
|
location = location.strip('/\\')
|
||||||
|
header, content = None, None
|
||||||
|
if location == 'directory':
|
||||||
|
header, content = self.handle_index(params)
|
||||||
|
elif location == 'img':
|
||||||
|
header, content = self.handle_image(params)
|
||||||
|
elif location in ['', 'index', 'index.html']:
|
||||||
|
header = HTTPResponseHeader(200)
|
||||||
|
content = loadfile(index_path).encode('utf-8')
|
||||||
|
else:
|
||||||
|
header = HTTPResponseHeader(404)
|
||||||
|
content = b'Please Do Not Try To Access Non-Image File!'
|
||||||
|
self.response(connection, header, content)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
args= sys.argv[1:]
|
||||||
|
|
||||||
|
port = 80
|
||||||
|
root = '.'
|
||||||
|
if len(args) > 0:
|
||||||
|
try:
|
||||||
|
port = int(args[0])
|
||||||
|
except Exception:
|
||||||
|
print('Port {0} not understood, use 80 instead'.format(args[0]), file=sys.stderr)
|
||||||
|
if len(args) > 1:
|
||||||
|
root = args[1]
|
||||||
|
if not os.path.isdir(root):
|
||||||
|
print('Path {0} is not a valid path, use current directory instead.'.format(root), file=sys.stderr)
|
||||||
|
root = '.'
|
||||||
|
|
||||||
|
print('Start HTTP server on port {0} and use web root as {1}'.format(port, root))
|
||||||
|
server = HTTPImageServer(bind_addr='0.0.0.0:{0}'.format(port), imgroot=root)
|
||||||
|
server.start(back=False)
|
||||||
Loading…
Reference in New Issue
Block a user