Fix multipart file upload handling in HTTP client#516
Open
BinoyOza-okta wants to merge 3 commits intomasterfrom
Open
Fix multipart file upload handling in HTTP client#516BinoyOza-okta wants to merge 3 commits intomasterfrom
BinoyOza-okta wants to merge 3 commits intomasterfrom
Conversation
- Fix Content-Type header handling for multipart/form-data requests - Add proper file data handling for binary uploads in aiohttp - Remove Content-Type header to allow aiohttp to set boundary automatically - Update form parameter processing to handle both dict and list formats - Support new tuple-based file upload format: [(field_name, (filename, filedata, mimetype))] This fixes the multipart upload endpoints for theme images (logo, favicon, background) where the Content-Type boundary was being overridden, causing "no multipart boundary param" errors. Fixes: Theme image upload endpoints returning 400 errors Related files: - okta/http_client.py - okta/api/themes_api.py
- Make Pillow an optional dependency (lazy import with try/except) - Remove Pillow from mandatory requirements, setup.py, pyproject.toml - Add extras_require so users can `pip install okta[images]` - Add logger.warning() when file type detection falls back - Fix mutable default args in RequestExecutor.create_request() - Fix param_serialize() docstring to match actual return signature - Use case-insensitive Content-Type header lookup for OAuth forms - Simplify JPEG detection to cover all SOI marker variants - Restore issue #131 reference comment for json param handling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix: Resolve multipart file upload failure for theme image endpoints
Problem
All theme image upload endpoints (
upload_brand_theme_logo,upload_brand_theme_favicon,upload_brand_theme_background_image) fail with HTTP 400 E0000019 Bad Request because file data is silently dropped during request construction.Root Cause — Two bugs in the request pipeline:
Generated API code discards
post_params: The Mustache template producedform = {}, overwriting the serialized file data returned byparam_serialize(). The file bytes were correctly encoded intopost_paramsbut never passed tocreate_request().http_client.pycannot handle the tuple-based file format: Even ifpost_paramswere passed,send_request()expectedrequest["form"]["file"]to be a file path string and would crash calling.split("/")on the(filename, bytes, mimetype)tuple format thatfiles_parameters()produces.Changes Made
Bug 1 Fix — Template + all 115 generated API files:
openapi/templates/api.mustache: Changedform = {}→form = post_params if post_params else Noneokta/api/*_api.pyfiles regenerated from the updated templateBug 2 Fix — HTTP client rewrite:
okta/http_client.py+openapi/templates/okta/http_client.mustache:_remove_content_type_header()helper for case-insensitive Content-Type removal (letsaiohttp.FormDataset its ownmultipart/form-data; boundary=...header per RFC 2046)[(field_name, (filename, bytes, mimetype)), ...]fromfiles_parameters()_default_headersapi_client.py+openapi/templates/api_client.mustache— Enhancedfiles_parameters():from PIL import Imageinsidetry/except ImportError— Pillow is not a required dependencylogger.warning()emitted when file type cannot be detected, with actionable install instructionsapplication/octet-stream(honest mimetype, server validates)param_serialize()docstring:return:to match the actual 5-element tuplerequest_executor.py+openapi/templates/okta/request_executor.mustache:headers: dict = {}→headers: dict = Nonewithif headers is None: headers = {}guardformparameter to docstring with both dict and list usage documentedDependencies:
requirements.txt,pyproject.toml)extras_require={"images": ["pillow >= 9.0.0"]}insetup.pyfor optional install viapip install okta[images]Affected Endpoints
POST /api/v1/brands/{brandId}/themes/{themeId}/logoPOST /api/v1/brands/{brandId}/themes/{themeId}/faviconPOST /api/v1/brands/{brandId}/themes/{themeId}/background-imagemultipart/form-datafile uploads via the generated API code pathUsage
Testing
upload_brand_theme_logo— PNG file → HTTP 201, CDN URL returnedupload_brand_theme_favicon— PNG file → HTTP 201, CDN URL returnedupload_brand_theme_background_image— JPG/PNG files → HTTP 201, CDN URL returnedform=Noneskipped cleanly)ImportErrorBreaking Changes
None. Fully backward compatible.