[BUG-305] Trying to send multipart/form-data

Here is an example function for performing "multipart/form-data" POST (file upload) using the urllib2 library (it uses only built-in libraries, does not require any external packages).

Note that the urllib2 documentation suggests "The Requests package is recommended for a higher-level HTTP client interface" but I was aiming for a solution that did not require import of any external packages, and this works.

This version is hard-coded for a content type of "audio/mpeg" but could be tweaked to use another content type.

Fill disclosure, this code was created with the assistance of ChatGPT after a good amount of coaxing (updated prompts) and manual tweaks.

My specific use case is uploading sound files to an Axis network speaker using it's Media Clip API within Ignition v8.1.28+.

import os
import urllib2
import base64

def upload_file(url, file_path, username, password):
    if not os.path.isfile(file_path):
        print("Error: File not found at {}".format(file_path))
        return

    try:
        # Open the file for reading
        with open(file_path, 'rb') as file_stream:
            file_data = file_stream.read()

        # Prepare the request
        request = urllib2.Request(url)
        boundary = "-----" + hex(hash(file_data))[2:]
        request.add_header("Content-Type", "multipart/form-data; boundary={}".format(boundary))

        # Encode credentials for basic authentication
        credentials = base64.b64encode("{}:{}".format(username, password))
        request.add_header("Authorization", "Basic {}".format(credentials))

        # Build the request body
        body = b''
        body += b"--" + boundary + b"\r\n"
        body += b"Content-Disposition: form-data; name=\"file\"; filename=\"{}\"\r\n".format(os.path.basename(file_path))
        body += b"Content-Type: audio/mpeg\r\n\r\n"
        body += file_data
        body += b"\r\n--" + boundary + b"--\r\n"

        # Set the request method and data
        request.get_method = lambda: 'POST'
        request.add_data(body)

        # Send the request
        response = urllib2.urlopen(request)

        # Print debug information, see https://docs.python.org/2/library/urllib2.html#urllib2.urlopen
        print "** DEBUG INFO - START, comment out in final code **"
        print "** URL:  ",  response.geturl()
        print "** Code: ", response.getcode()
        print "** Info: \n", response.info()
        print "** DEBUG INFO - END\n"

        # Get the response code
        response_code = response.getcode()
        if response_code == 200:
            print("File uploaded successfully.")
        else:
            print("Error: Failed to upload file. Response code: {}".format(response_code))
		
    except Exception as e:
        print("Error: {}".format(e))