Repository navigation
Conversation
Since the v37 generator, create_* and delete_* operations whose OpenAPI consumes is */* serialize a JSON body and omit Content-Type. v36 set that header in rest.py. An intermediary that guesses a type for a bare string body, such as urllib3-future, then sends text/plain and the API server returns 415. When RESTClientObject JSON-serializes a body (body is not None) and no Content-Type is present in any casing, set application/json. Leave body-less requests unchanged: RFC 9110 section 8.3 only asks for the header when the message has content. Keep an explicit media type, including a lowercase header name, and copy the header map before inserting the default so request() does not mutate the caller's dict. Generated *_api.py serializers still ignore _content_type for */* operations; those files are regenerated, and _headers remains the override. kubernetes.aio already defaults the header. Refresh scripts/rest_client_patch.diff and move the client-go retry hunk so update-client.sh applies the stack with no offset.
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: eisen0419 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Welcome @eisen0419! |
What type of PR is this?
/kind bug
/kind regression
What this PR does / why we need it:
Summary
Since v37.0.0, generated
create_*anddelete_*methods whose OpenAPIconsumesis["*/*"]serialize a JSON body without settingContent-Type, causing strict HTTP stacks/intermediaries (such asurllib3-future/niquests) to defaultstrbodies totext/plainand fail with415 Unsupported Media Type.When
RESTClientObject.requestJSON-serializes a non-Nonebody and noContent-Typeheader is present in any casing, defaultContent-Typetoapplication/jsonon a shallow copy ofheaders, while keeping body-less requests unchanged and keepingscripts/rest_client_patch.diffandscripts/client_go_retry_patch.diffsynchronized withscripts/update-client.sh.RESTClientObject.request(method, url, headers, body, ...) method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE'] - content_type = headers.get('Content-Type') + content_type_key, content_type = find_header_case_insensitive(headers, 'content-type') if is_json or is_structured_yaml: if body is not None: request_body = json.dumps(body) + if content_type_key is None: + headers = dict(headers) + headers['Content-Type'] = 'application/json'Evidence
Merge Danger
Door: two-way
Scoped to
RESTClientObject.requestand its corresponding regeneration patch stack (scripts/rest_client_patch.diff,scripts/client_go_retry_patch.diff).Blast Radius: narrow
Only adds
Content-Type: application/jsonwhenrest.pyhas alreadyjson.dumps-serialized a non-Nonerequest body and noContent-Typeheader (in any casing) was supplied; body-less requests and explicit media types are untouched.Which issue(s) this PR fixes:
Fixes #2782
Special notes for your reviewer:
scripts/rest_client_patch.diffand the line offset inscripts/client_go_retry_patch.diffwere verified via a full reverse/forwardgit applyround-trip matchingscripts/update-client.sh.Does this PR introduce a user-facing change?
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.: