Skip to content

Instantly share code, notes, and snippets.

@MichaelCurrie
Last active December 11, 2024 18:22
Show Gist options
  • Select an option

  • Save MichaelCurrie/19394abc19abd0de4473b595c0e37a3a to your computer and use it in GitHub Desktop.

Select an option

Save MichaelCurrie/19394abc19abd0de4473b595c0e37a3a to your computer and use it in GitHub Desktop.
Drag-and-drop upload files, via JavaScript, to a simple Python 3 HTTP server
#Drag-and-drop upload files, via JavaScript, to a simple Python 3 HTTP server
body {
font-family: "Arial", sands-serif;
}
.dropzone {
width: 300px;
height: 300px;
border: 2px dashed #ccc;
color: #ccc;
line-height: 300px;
text-align: center;
}
.dropzone.dragover {
border-color: #000;
color: #000;
}
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Drag n' Drop</title>
<link rel="stylesheet" type="text/css" href="dropzone.css" />
<script src="dropzone.js"></script>
</head>
<body>
<h1 id="title">Let's try some drag and drop uploading!</h1>
<div id="dropzone_element" class="dropzone">
Drop files here to upload
</div>
<div id="upload_results_element">
</div>
</body>
</html>
// Handle drag and drop into a dropzone_element div:
// send the files as a POST request to the server
"use strict";
// Only start once the DOM tree is ready
if(document.readyState === "complete") {
createDropzoneMethods();
} else {
document.addEventListener("DOMContentLoaded", createDropzoneMethods);
}
function createDropzoneMethods() {
let dropzone = document.getElementById("dropzone_element");
dropzone.ondragover = function() {
this.className = "dropzone dragover";
return false;
}
dropzone.ondragleave = function() {
this.className = "dropzone";
return false;
}
dropzone.ondrop = function(e) {
// Stop browser from simply opening that was just dropped
e.preventDefault();
// Restore original dropzone appearance
this.className = "dropzone";
upload_files(e.dataTransfer.files)
}
}
function upload_files(files) {
let upload_results = document.getElementById("upload_results_element");
let formData = new FormData(),
xhr = new XMLHttpRequest();
console.log("Dropped " + String(files.length) + " files.");
for(let i=0; i<files.length; i++) {
formData.append("file", files[i]);
}
xhr.onreadystatechange = function() {
if(xhr.readyState === XMLHttpRequest.DONE) {
alert(xhr.responseText);
}
console.log(xhr.response);
upload_results.innerHTML = this.response;
}
console.log("Let's upload files: ", formData);
xhr.open('POST', 'upload_handler.py', true); // async = true
xhr.send(formData);
}
# -*- coding: utf-8 -*-
import re
import sys
import os
import json
from http.server import SimpleHTTPRequestHandler, HTTPServer
class FileUploadHTTPRequestHandler(SimpleHTTPRequestHandler):
"""An HTTP Server that accepts POST requests and saves them as
files in the same folder as this script.
"""
protocol_version = "HTTP/1.1"
def do_POST(self):
"""Handle a POST request."""
# Save files received in the POST
wasSuccess, files_uploaded = self.handle_file_uploads()
# Compose a response to the client
response_obj = {
"wasSuccess": wasSuccess,
"files_uploaded": files_uploaded,
"client_address": self.client_address
}
response_str = json.dumps(response_obj)
self.log_message(response_str)
# Send our response code, header, and data
self.send_response(200)
self.send_header("Content-type", "Application/json")
self.send_header("Content-Length", len(response_str))
self.end_headers()
self.wfile.write(response_str.encode('utf-8'))
def read_line(self):
line_str = self.rfile.readline().decode('utf-8')
self.char_remaining -= len(line_str)
return line_str
def handle_file_uploads(self):
"""
Take the post request and save any files received to the same folder
as this script.
Returns
wasSuccess: bool: whether the process was a success
files_uploaded: list of string: files that were created
"""
self.char_remaining = int(self.headers['content-length'])
# Find the boundary from content-type, which might look like:
# 'multipart/form-data; boundary=----WebKitFormBoundaryUI1LY7c2BiEKGfFk'
boundary = self.headers['content-type'].split("=")[1]
basepath = self.translate_path(self.path)
# Strip this script's name from the path so it's just a folder
basepath = os.path.dirname(basepath)
# ----WebKitFormBoundaryUI1LY7c2BiEKGfFk
line_str = self.read_line()
if not boundary in line_str:
self.log_message("Content did NOT begin with boundary as " +
"it should")
return False, []
files_uploaded = []
while self.char_remaining > 0:
# Breaking out of this loop on anything except a boundary
# an end-of-file will be a failure, so let's assume that
wasSuccess = False
# Content-Disposition: form-data; name="file"; filename="README.md"
line_str = self.read_line()
filename = re.findall('Content-Disposition.*name="file"; ' +
'filename="(.*)"', line_str)
if not filename:
self.log_message("Can't find filename " + filename)
break
else:
filename = filename[0]
filepath = os.path.join(basepath, filename)
try:
outfile = open(filepath, 'wb')
except IOError:
self.log_message("Can't create file " + str(filepath) +
" to write; do you have permission to write?")
break
# Content-Type: application/octet-stream
line_str = self.read_line()
# Blank line
line_str = self.read_line()
# First real line of code
preline = self.read_line()
# Loop through the POST until we find another boundary line,
# signifying the end of this file and the possible start of another
while self.char_remaining > 0:
line_str = self.read_line()
# ----WebKitFormBoundaryUI1LY7c2BiEKGfFk
if boundary in line_str:
preline = preline[0:-1]
if preline.endswith('\r'):
preline = preline[0:-1]
outfile.write(preline.encode('utf-8'))
outfile.close()
self.log_message("File '%s' upload success!" % filename)
files_uploaded.append(filename)
# If this was the last file, the session was a success!
wasSuccess = True
break
else:
outfile.write(preline.encode('utf-8'))
preline = line_str
return wasSuccess, files_uploaded
if __name__ == "__main__":
httpd = HTTPServer(("", 8000), FileUploadHTTPRequestHandler)
sa = httpd.socket.getsockname()
print("Serving HTTP on", sa[0], "port", sa[1], "...")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("\nKeyboard interrupt received, exiting.")
httpd.server_close()
sys.exit(0)
@venkatDesh
Copy link
Copy Markdown

@MichaelCurrie i got the solution for that problem.By the wayThankyou for your reply.
I just changed the encode and decode method in upload_handle.py from 'utf-8' to 'ISO-8859-1' and it works fine.
And one more thing what if i want to custmozie the upload location while dragging do you have any idea for that?.

@MichaelCurrie
Copy link
Copy Markdown
Author

MichaelCurrie commented Sep 7, 2019

If you mean customize the place on the server the files are saved, you just need to change these lines:

basepath = self.translate_path(self.path)
# Strip this script's name from the path so it's just a folder
basepath = os.path.dirname(basepath)

To a hardcoded basepath:

basepath = os.path.join('C', 'venkatDesh', 'havefun')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment