Issue 1:
I made a test code for this issue. I made a custom class because I want server to return jsonified list if view function returns list. It works on flask 1.0.2 but it doesn't work on the new flask version (1.1.1)

from flask import Flask, Response, jsonify

class CustomResponse(Response):
@classmethod
def force_type(cls, response, environ=None):
if isinstance(response, list):
return jsonify(response)
return super(CustomResponse, cls).force_type(response, environ)

app = Flask(__name__)
app.response_class = CustomResponse

@app.route('/', methods=['GET'])
def response_list():
return ['it', 'is', 'test']

if __name__ == '__main__':
app.run(host='127.0.0.1')

On 1.0.2 version,

# evaluate a WSGI callable, or coerce a different response
# class to the correct type
try:
rv = self.response_class.force_type(rv, request.environ)
except TypeError as e:
new_error = TypeError(
'{e}\nThe view function did not return a valid'
' response. The return type must be a string, tuple,'
' Response instance, or WSGI callable, but it was a'
' {rv.__class__.__name__}.'.format(e=e, rv=rv)
)

flask changes type forcely by calling force_type of response_class, but newest version doesn't change. (code below)

if isinstance(rv, (text_type, bytes, bytearray)):
# let the response class set the status and headers instead of
# waiting to do it manually, so that the class can handle any
# special logic
rv = self.response_class(rv, status=status, headers=headers)
status = headers = None
elif isinstance(rv, dict):
rv = jsonify(rv)
elif isinstance(rv, BaseResponse) or callable(rv):
# evaluate a WSGI callable, or coerce a different response
# class to the correct type
try:
rv = self.response_class.force_type(rv, request.environ)
except TypeError as e:
new_error = TypeError(
"{e}\nThe view function did not return a valid"
" response. The return type must be a string, dict, tuple,"
" Response instance, or WSGI callable, but it was a"
" {rv.__class__.__name__}.".format(e=e, rv=rv)
)
reraise(TypeError, new_error, sys.exc_info()[2])
else:
raise TypeError(
"The view function did not return a valid"
" response. The return type must be a string, dict, tuple,"
" Response instance, or WSGI callable, but it was a"
" {rv.__class__.__name__}.".format(rv=rv)
)

Is it intended or just a bug?

Expected

When I call 127.0.0.1:5000,

['it', 'is', 'test']

Actual

[2019-07-10 16:36:33,554] ERROR in app: Exception on / [GET]
Traceback (most recent call last):
File "C:\Users\Mapia\Desktop\develop\study\flask.py\venv\lib\site-packages\flask\app.py", line 2446, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\Mapia\Desktop\develop\study\flask.py\venv\lib\site-packages\flask\app.py", line 1952, in full_dispatch_request
return self.finalize_request(rv)
File "C:\Users\Mapia\Desktop\develop\study\flask.py\venv\lib\site-packages\flask\app.py", line 1967, in finalize_request
response = self.make_response(rv)
File "C:\Users\Mapia\Desktop\develop\study\flask.py\venv\lib\site-packages\flask\app.py", line 2130, in make_response
" {rv.__class__.__name__}.".format(rv=rv)
TypeError: The view function did not return a valid response. The return type must be a string, dict, tuple, Response instance, or WSGI callable, but it was a list.
127.0.0.1 - - [10/Jul/2019 16:36:33] "GET / HTTP/1.1" 500 -

Environment

Python version: 3.7.3

Flask version: 1.1.1

Werkzeug version: 0.15.4

Issue 2:
Expected Behavior

from flask import Flask
app = Flask(__name__)
@app.route('/')
def issue():
return {'test': 'test'}, {'Content-Type': 'test'}

Using curl -v http://127.0.0.1:5000/ to query the view I expect only one Content-Type header > Content-Type: test

Actual Behavior

Duplicate headers are returned

< Content-Type: application/json
< Content-Type: test

Environment

Python version: 3.8.2

Flask version: 1.1.2

Werkzeug version: 1.0.1

Context

This issue also effects responses created with make_response when using a dict or jsonify body + the headers argument with a 'Content-Type':

from flask import Flask, make_response
app = Flask(__name__)
@app.route('/')
def issue():
return make_response({'test': 'test'}, {'Content-Type': 'test'})

This issue is caused by jsonify adding a 'Content-Type' header then make_response uses extent to add the additional headers, thus leading to the duplicate.

Returning a str/bytes body does not have this problem as no 'Content-Type' is added by flask, if one is missing it is added by werkzeug.

The reason I came across this issue is we have older code which does return json.dumps(data), 200, {'Content-Type': 'application/json+somecustomtype'} and I assumed based on the flask docs that just returning the data and letting flask do the jsonify would be better.