4

I've created a Cloud Function on Azure with an HTTP trigger and I want to be able to handle a file upload using a form.
My entry point looks like this:

def main(req: func.HttpRequest) -> func.HttpResponse:
    body = req.get_body()
    headers=req.headers
    ...

The problem is that what I get in body is raw binary and I don't know how to decode it and get the uploaded file.

Does anyone know about a good method to achieve this?

1

3 Answers 3

9

There's, I'd say, an Azure-native way to do that, and there's a Python-native way.

Azure-native method

azure.functions.HttpRequest has a files property which is a MultiDict generator. Here's how to use that:

import logging

import azure.functions as func


def main(req: func.HttpRequest) -> func.HttpResponse:
    for input_file in req.files.values():
        filename = input_file.filename
        contents = input_file.stream.read()

        logging.info('Filename: %s' % filename)
        logging.info('Contents:')
        logging.info(contents)

        [..process the file here as you want..]

    return func.HttpResponse(f'Done\n')

Python-native method

If you want to do it only with the standard Python library (e.g. for more portability), then you should know that what you need to parse in the body is the MIME multipart message, in a binary form:

Content-Type: multipart/form-data; boundary=--------------------------1715cbf149d89cd9

--------------------------1715cbf149d89cd9
Content-Disposition: form-data; name="data"; filename="test.txt"
Content-Type: application/octet-stream

this is a test document

--------------------------1715cbf149d89cd9--

Sample script to reproduce:

echo 'this is a test document' > test.txt && curl -F '[email protected]' 'https://[..yourfunctionname..].azurewebsites.net/api/HttpTrigger'

You will be surprised but the email module would do it for you (I personally think it's poorly named).

Sample code below (note: with no error handling!) to highlight the core idea:

import cgi
import email
import logging

import azure.functions as func


def main(req: func.HttpRequest) -> func.HttpResponse:
    # Content-Type should be 'multipart/form-data' with some boundary
    content_type = req.headers.get('Content-Type')
    body = req.get_body().decode('utf-8')

    mime_template = 'MIME-Version: 1.0\nContent-Type: %s\n%s'
    post_data = email.parser.Parser().parsestr(mime_template % (content_type, body))

    # Content-Disposition header format:
    #  'form-data; name="data"; filename="test.txt"'
    disposition = post_data.get_payload()[0]['Content-Disposition']
    disposition_value = cgi.parse_header('Content-Disposition: %s' % disposition)[1]

    filename = disposition_value['filename']
    contents = post_data.get_payload()[0].get_payload()

    logging.info('Filename: %s' % filename)
    logging.info('Contents:')
    logging.info(contents)

    [..process the file here as you want..]

    return func.HttpResponse(f'Done\n')
Sign up to request clarification or add additional context in comments.

Comments

0
+500

I think the best way to tackle is to conver those binary data to a file and then upload to blob storage,

        #upload to picture to blob storage
        block_blob_service = BlockBlobService(account_name=accuntName, account_key=accuntKey)
        container_name = 'machineimages'
        blob_name = image_name + '.jpeg'
        # Creating the blob
        block_blob_service.create_blob_from_bytes(container_name, blob_name, decoded_image,
        content_settings=ContentSettings(content_type='image/png'))
        logging.info("Successfull blob creating ")

        # Returning a succesful post request 
        return func.HttpResponse(f"successful request")

Here is a sample .

1 Comment

if you want the content you can also do github.com/windperson/PythonAzureFunctionDemo/blob/…
0

apparently, neither create_blob_from_bytes nor BlobServiceClient exist in the latest python SDK which we get by default.

So I had to take a detour to do this.

    from azure.storage.blob import (
        BlobServiceClient,
        ContentSettings
    )
    # decoding base64 image from json body
    decoded_image = base64.b64decode(image)
    blob_service_client = BlobServiceClient.from_connection_string(
        conn_str=storage_connection_string
        )
    logging.debug(f'getting client for container : {container_name}')
    container_client = 
    blob_service_client.get_container_client(container=container_name)
    blob_client = container_client.get_blob_client(blob_name)
    if blob_client.exists():
        blob_client.delete_blob()
    blob_client = blob_service_client.get_blob_client(container=container_name, 
    blob=blob_name)
    try:
        blob_client.upload_blob(decoded_image)
        content_settings =ContentSettings(content_type='image/png')
        logging.debug(f'setting the content type : {content_settings}')
    except Exception as e:
        logging.error(str(e))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.