Skip to content

Instantly share code, notes, and snippets.

@Scarygami
Created April 25, 2013 13:16
Show Gist options
  • Save Scarygami/5459611 to your computer and use it in GitHub Desktop.
Save Scarygami/5459611 to your computer and use it in GitHub Desktop.
Handling multipart/related or multipart/mixed requests, comparable to mediaupload requests of some Google APIs (https://developers.google.com/glass/media-upload#multipart), using webapp2 and the email library on App Engine
application: upload-test
version: 1
runtime: python27
threadsafe: true
api_version: 1
handlers:
- url: .*
script: main.app
#!/usr/bin/python
# Copyright (C) 2013 Gerwin Sturm, FoldedSoft e.U.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
__author__ = '[email protected] (Gerwin Sturm)'
import webapp2
import email
import json
class UploadHandler(webapp2.RequestHandler):
def post(self):
# Check if we are receiving a valid content_type
content_type = self.request.content_type
if content_type != "multipart/related" and content_type != "multipart/mixed":
self.response.out.write("Invalid Content-Type")
# Attach content-type header to body so that email library can decode it correctly
message = "Content-Type: " + self.request.headers["Content-Type"] + "\r\n"
message += self.request.body
msg = email.message_from_string(message)
if not msg.is_multipart():
self.response.out.write("Couldn't decode multipart body")
return
for payload in msg.get_payload():
if payload.get_content_type().startswith("image/"):
# Display attached image
self.response.out.write("<img src=\"data:%s;base64,%s\"><br><br>" % (payload.get_content_type(), payload.get_payload()))
elif payload.get_content_type() == "application/json":
# Parse and display JSON metadata
j = json.loads(payload.get_payload())
self.response.out.write("<pre>" + json.dumps(j, indent=2, separators=(",", ": ")) + "</pre><br><br>")
else:
self.response.out.write("Invalid content-type: %s<br><br>" % payload.get_content_type())
class IndexHandler(webapp2.RequestHandler):
def get(self):
boundary = "-----1234567890"
# Load image data here, using an amazing dot image to keep the string short here
image_type = "image/png"
base64_data = "iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAgUlEQVQIHWNgYGBgYuVjXinqwPdfzInvO6sA82SQ2P///xkYQRyNCukUNkEWDqAgw6/3f37caHu66dfHP+FMgkbccAmQJEiRgBF3GIjN9P8fA1gHiAMDjEwMP0Fspg/nvq4CGQWTALHfn/s6G8ZnAtkLdMwPkKNAjgNpAjsIROACABtKMFgDnRCzAAAAAElFTkSuQmCC"
# JSON Metadata
metadata = {
"text": "Image upload",
"author": "Me"
}
request = webapp2.Request.blank("/upload")
request.method = "POST"
# Construct multi-part requestbody
request.body = "\r\n--" + boundary + "\r\n"
request.body += "Content-Type: application/json\r\n\r\n"
request.body += json.dumps(metadata)
request.body += "\r\n--" + boundary + "\r\n"
request.body += "Content-Type: " + image_type + "\r\n"
request.body += "Content-Transfer-Encoding: base64\r\n\r\n"
request.body += base64_data
request.body += "\r\n\r\n--" + boundary + "--"
request.headers["Content-Type"] = "multipart/related; boundary=\"" + boundary + "\""
response = request.get_response(app)
self.response.out.write(response.body)
app = webapp2.WSGIApplication(
[("/", IndexHandler), ("/upload", UploadHandler)],
debug=True
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment