GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-135056: Add a --header CLI argument to http.server by aisipos · Pull Request #135057 · python/cpython

Conversation

@aisipos

@aisipos aisipos commented Jun 3, 2025 •
edited by github-actions Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

As proposed in #135056, Add a --cors command line argument to the stdlib http.server module, which will add an Access-Control-Allow-Origin: * header to all responses.

Invocation:

python -m http.server --cors

As part of this implementation, add a response_headers argument to SimpleHTTPRequestHandler and HTTPServer, which allows callers to add addition headers to the response. Ideally it would have been possible to just have made a CorsHttpServer class, but a couple of issues made that difficult:

  • The http.server CLI uses more than one HTTP Server class, in order to support TLS/HTTPS. So a single CorsHttpServer child class wouldn't work to support both use cases.
  • Much of the work in specifying HTTP behavior is handled by the various RequestHandler classes. However, the HttpServer classes didn't have an easy way to pass arguments down into the instantiated handlers.

As a result, this PR updates both HTTPServer and SimpleHTTPRequestHandler to accept a response_headers argument, which allows callers to specify an additional set of HTTP headers to pass in the response.

  • HTTPServer now overrides finish_request to pass this new kwarg down to its RequestHandler.
  • SimpleHTTPRequestHandler now accepts a resposnse_headers kwarg, to optionally specify a dictionary of additional headers to send in the response.

Care is taken to not pass the response_headers argument to any instance constructors when not provided, to ensure backwards compatibility. I tried to keep the implementation as short and simple as possible.

With the addition of a response_headers argument, we allow ourselves to have a future possible custom header http argument, such as:

python -m http.server -H 'custom-header: custom-value'
  • Issue: Add a --cors command line option to stdlib http.server #135056

📚 Documentation preview 📚: https://cpython-previews--135057.org.readthedocs.build/

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@python-cla-bot

python-cla-bot Bot commented Jun 3, 2025 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot added the awaiting review label Jun 3, 2025
@bedevere-app

bedevere-app Bot commented Jun 3, 2025

Copy link
Copy Markdown

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot mentioned this pull request Jun 3, 2025
Add a --cors command line option to stdlib http.server #135056
Closed
@aisipos
pythongh-135056: Add a --cors CLI argument to http.server
0d02fbe
Add a --cors command line argument to the stdlib http.server module, which will
add an `Access-Control-Allow-Origin: *` header to all responses. As part of this
implementation, add a `response_headers` argument to SimpleHTTPRequestHandler
and HttpServer, which allows callers to add addition headers to the response.
@aisipos
aisipos force-pushed the https-server-cors-issue-135056 branch from 3f11652 to 0d02fbe Compare June 3, 2025 05:24
hugovk
hugovk reviewed Jun 3, 2025
View reviewed changes

@hugovk hugovk left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I'd prefer a general headers option, but will comment on the issue or Discourse topic)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Doc/library/http.server.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Doc/library/http.server.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Doc/library/http.server.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Misc/NEWS.d/next/Library/2025-06-02-22-23-38.gh-issue-135056.yz3dSs.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Misc/NEWS.d/next/Library/2025-06-02-22-23-38.gh-issue-135056.yz3dSs.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@aisipos
gh-issue-135056: Fix doc versionchanged and NEWS entries.
1838da7
@aisipos

aisipos commented Jun 3, 2025

Copy link
Copy Markdown
Contributor Author

test_wsgiref is failing. I'll look into it.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aisipos
pythongh-13056: Allow unspecified response_headers in HTTPServer.
a3256fd
This fixes the breakage to HttpServer as used by wsgiref.
@aisipos

aisipos commented Jun 3, 2025

Copy link
Copy Markdown
Contributor Author

test_wsgiref fixed in a3256fd. This should fix any backwards incompatibility errors erroneously introduced in the first commit.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@donbarbos

donbarbos commented Jun 3, 2025

Copy link
Copy Markdown
Contributor

I think it's worth adding to this What's New entry (./Doc/whatsnew/3.15.rst)

hugovk reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Zheaoli

Zheaoli commented Jun 6, 2025

Copy link
Copy Markdown
Contributor

For me, I don't think add --cors CLI argument would be a good idea. Base on following reasons:

  1. The CORS policy is a complicated idea. Six response headers are included by the word(If I'm correct). If you set the Access-Control-Allow-Origin, and now the people may need Access-Control-Allow-Methods( Allow for OPTION method). What is the next argument we need to add?
  2. The CLI for http.server is just for a debug target. So we design the CLI as simple as we can. The developer don't need to care about any extra detail when they run just a simple debug server.
  3. if we need CORS policy in the future. I suggest we setup all the header for developer and don't need to add cli for it.
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aisipos
aisipos requested a review from hugovk June 6, 2025 23:05
@picnixz
picnixz self-requested a review June 7, 2025 23:15
@hugovk

hugovk commented Jun 9, 2025

Copy link
Copy Markdown
Member

@Zheaoli Please comment in the discussion thread: https://discuss.python.org/t/any-interest-in-adding-a-cors-option-to-python-m-http-server/92120.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@hugovk

hugovk commented Jun 9, 2025

Copy link
Copy Markdown
Member

(I'd prefer a general headers option, but will comment on the issue or Discourse topic)

https://discuss.python.org/t/any-interest-in-adding-a-cors-option-to-python-m-http-server/92120/24

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

picnixz
picnixz reviewed Jun 9, 2025
View reviewed changes

@picnixz picnixz left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very fond of how the HTTP server class is growing more and more with more __init__ parameters, but I don't have a better idea for now. Maybe a generic configuration object but this would be an overkill for this class in particular I think.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Doc/library/http.server.rst Outdated

.. versionadded:: 3.14

.. option:: --cors

@picnixz picnixz Jun 7, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As Hugo said, since we're anyway exposing response-headers, I think we should also expose it from the CLI. It could be useful for users in general (e.g., --add-header NAME VALUE with the -H alias).

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Misc/NEWS.d/next/Library/2025-06-02-22-23-38.gh-issue-135056.yz3dSs.rst Outdated
@@ -0,0 +1,2 @@
Add a ``--cors`` cli option to :program:`python -m http.server`. Contributed by

@picnixz picnixz Jun 7, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also update What's New/3.15.rst

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@aisipos aisipos Jun 20, 2025

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used blurb to make this entry in NEWS.d, not knowing when it's appropriate to edit the main 3.15.rst file. I think once we know if we're doing --cors / --header , or both, I can make the appropriate update to What's New/3.15.rst

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

picnixz reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
Comment thread Lib/http/server.py Outdated
def __init__(self, server_address, RequestHandlerClass,
bind_and_activate=True, *, certfile, keyfile=None,
password=None, alpn_protocols=None):
password=None, alpn_protocols=None, response_headers=None):

@picnixz picnixz Jun 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
password=None, alpn_protocols=None, response_headers=None):
password=None, alpn_protocols=None, **http_server_kwargs):

And pass http_server_kwargs to super()

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/http/server.py Outdated
Comment on lines +133 to +138
args = (request, client_address, self)
kwargs = {}
response_headers = getattr(self, 'response_headers', None)
if response_headers:
kwargs['response_headers'] = self.response_headers
self.RequestHandlerClass(*args, **kwargs)

@picnixz picnixz Jun 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
args = (request, client_address, self)
kwargs = {}
response_headers = getattr(self, 'response_headers', None)
if response_headers:
kwargs['response_headers'] = self.response_headers
self.RequestHandlerClass(*args, **kwargs)
kwargs = {}
if hasattr(self, 'response_headers'):
kwargs['response_headers'] = self.response_headers
self.RequestHandlerClass(request, client_address, self, **kwargs)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@aisipos aisipos Jun 20, 2025

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@picnixz I made this requested change in 77b5fff. Note though that now HTTPServer will pass response_headers to the RequestHandler class even if response_headers is None or {}. Most RequestHandler implementation constructor implementations don't take this argument, so in order for this to work I added **kwargs as an argument to BaseRequestHandler.__init__. My earlier implementation was trying to prevent this, to keep any changes to only http/server.py and not need to touch anything in socketserver.py. Perhaps the **kwargs addition is ok, or I'm open to other solutions if we can think of better ones.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/http/server.py Outdated
Comment on lines +708 to +712
def __init__(self, *args, directory=None, response_headers=None, **kwargs):
if directory is None:
directory = os.getcwd()
self.directory = os.fspath(directory)
self.response_headers = response_headers or {}

@picnixz picnixz Jun 9, 2025 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def __init__(self, *args, directory=None, response_headers=None, **kwargs):
if directory is None:
directory = os.getcwd()
self.directory = os.fspath(directory)
self.response_headers = response_headers or {}
def __init__(self, *args, directory=None, response_headers=None, **kwargs):
if directory is None:
directory = os.getcwd()
self.directory = os.fspath(directory)
self.response_headers = response_headers

You're already checking for is not None later

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/http/server.py Outdated
ServerClass=ThreadingHTTPServer,
protocol="HTTP/1.0", port=8000, bind=None,
tls_cert=None, tls_key=None, tls_password=None):
tls_cert=None, tls_key=None, tls_password=None, response_headers=None):

@picnixz picnixz Jun 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
tls_cert=None, tls_key=None, tls_password=None, response_headers=None):
tls_cert=None, tls_key=None, tls_password=None,
response_headers=None):

Let's group the parameters per purpose

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/http/server.py Outdated
Comment on lines +1078 to +1082
handler_args = (request, client_address, self)
handler_kwargs = dict(directory=args.directory)
if self.response_headers:
handler_kwargs['response_headers'] = self.response_headers
self.RequestHandlerClass(*handler_args, **handler_kwargs)

@picnixz picnixz Jun 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
handler_args = (request, client_address, self)
handler_kwargs = dict(directory=args.directory)
if self.response_headers:
handler_kwargs['response_headers'] = self.response_headers
self.RequestHandlerClass(*handler_args, **handler_kwargs)
self.RequestHandlerClass(request, client_address, self,
directory=args.directory,
response_headers=self.response_headers)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_httpservers.py Outdated
)
else:
self.server = HTTPServer(('localhost', 0), self.request_handler)
self.server = HTTPServer(('localhost', 0), self.request_handler,

@picnixz picnixz Jun 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You must also modify create_https_server appropriately

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_httpservers.py Outdated
Comment on lines +832 to +834
server_kwargs = dict(
response_headers = {'Access-Control-Allow-Origin': '*'}
)

@picnixz picnixz Jun 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
server_kwargs = dict(
response_headers = {'Access-Control-Allow-Origin': '*'}
)
server_kwargs = {
'response_headers': {'Access-Control-Allow-Origin': '*'}
}

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_httpservers.py Outdated
server_kwargs = dict(
response_headers = {'Access-Control-Allow-Origin': '*'}
)
def test_cors(self):

@picnixz picnixz Jun 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_cors(self):
def test_cors(self):

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
aisipos added 2 commits June 19, 2025 18:49
@aisipos
pythongh-135056: Simplifications and cleanups to http cors changes.
77b5fff
@aisipos
pythongh-135056: Add a --header argument to http.server cli.
5f89c97
@aisipos
aisipos force-pushed the https-server-cors-issue-135056 branch from 3024d3d to 5f89c97 Compare June 20, 2025 01:50
@aisipos

aisipos commented Jun 20, 2025 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

@picnixz I have made all your suggested changes in 77b5fff . I have also implemented a generic -H or --header cli argument in 5f89c97. Now this PR contains both --cors and --header. I don't know if we want both, there doesn't seem to yet be consensus on what we prefer, although Core devs so far seem to lean on just --header.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@hugovk

hugovk commented Jun 20, 2025

Copy link
Copy Markdown
Member

I think we should just have --header, as that unlocks the ability to enable CORS. We can still add --cors later if there's demand and consensus.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@hugovk

hugovk commented Jun 20, 2025

Copy link
Copy Markdown
Member

And what are your thoughts on positional args like HTTPie?

https://discuss.python.org/t/any-interest-in-adding-a-cors-option-to-python-m-http-server/92120/24

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

vadmium
vadmium reviewed Jun 22, 2025
View reviewed changes
Comment thread Doc/library/http.server.rst Outdated
Support of the ``'If-Modified-Since'`` header.

.. versionchanged:: next
Support ``response_headers`` as an instance argument.

@vadmium vadmium Jun 9, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn’t this redundant with the entry already under the constructor heading?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@aisipos aisipos Jul 10, 2025

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps - it seems the constructor documentation is used to make a brief mention of each argument and when it was added, with more detail being filled in later. My latest commits make several changes requested elsewhere for other reasons, but if the current version is still too redundant in multiple places I can make some more edits.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@picnixz picnixz Aug 18, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should add this information. There is no notion of an "instance argument": it should rather be an instance attribute, and this should be documented through a .. attribute::, below .. attribute:: extensions_map

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/http/server.py Outdated
self.RequestHandlerClass(request, client_address, self,
directory=args.directory)
directory=args.directory,
response_headers=self.response_headers)

@vadmium vadmium Jun 20, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not do this the same way the --directory or --protocol options are implemented? Either way should avoid adding internal parameters to unrelated HTTPServer and BaseRequestHandler classes.

You could build the response_headers dictionary before the DualStackServerMixin class, and then pass it by referencing the outer scope like is already done with args.directory:

Suggested change
response_headers=self.response_headers)
response_headers=response_headers)

Or set the response_headers attribute on the SimpleHTTPRequestHandler class rather than in its constructor, like is done for protocol_verison in the test function.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@aisipos aisipos Jul 10, 2025

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed your advice, see b1026d2. I made response_headers an argument to SimpleHTTPRequestHandler only, and send the argument to it in the DualStackServerMixin class.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Doc/library/http.server.rst Outdated
The *directory* parameter accepts a :term:`path-like object`.

.. versionchanged:: next
The *response_headers* parameter accepts an optional dictionary of

@vadmium vadmium Jun 22, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In previous versions, this was not a valid parameter at all.

Suggested change
The *response_headers* parameter accepts an optional dictionary of
Added *response_headers*, which accepts an optional dictionary of

Also, did you consider accepting a list or iterable of (name, value) pairs instead, like returned by http.client.HTTPResponse.getheaders? That would be better for sending multiple Set-Cookie fields.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@aisipos aisipos Jul 10, 2025

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, sending multiple headers of the same name would indeed be necessary. I updated to use an iterable of name value pairs instead in 7a793f2

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Doc/library/http.server.rst Outdated

.. versionchanged:: next
The *response_headers* parameter accepts an optional dictionary of
additional HTTP headers to add to each response.

@vadmium vadmium Jun 22, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth clarifying how these fields interact with other fields such as Server specified under BaseHTTPRequestHandler.send_response, and Last-Modified under do_GET.

Also clarify which responses the fields are included in, assuming it wasn’t your intention to include them for 404 Not Found, 304 Not Modified, lower-level errors, etc.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@aisipos aisipos Jul 10, 2025

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the latest commits, I've noted that the custom headers are only sent in success cases. What do you mean by interaction though? The custom headers currently get sent after Last-Modified, should I mention the placement of the custom headers and that they appear after Last-Modified?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/http/server.py Outdated
Comment on lines +754 to +756
if self.response_headers is not None:
for header, value in self.response_headers.items():
self.send_header(header, value)

@vadmium vadmium Jun 22, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is moving this to an extended send_response override an option? That way you would include the fields for all responses.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/http/server.py Outdated
if directory is None:
directory = os.getcwd()
self.directory = os.fspath(directory)
self.response_headers = response_headers

@vadmium vadmium Jun 22, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify as an internal private attribute:

Suggested change
self.response_headers = response_headers
self._response_headers = response_headers

Or document SimpleHTTPRequestHandler.response_headers as a public attribute.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@aisipos aisipos Jul 10, 2025

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far I have intended response_headers to be a public attribute. Do you mean add documentation to the docstring of SimpleHTTPRequestHandler or more documentation in Doc/library/http.server.rst?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_httpservers.py Outdated
else:
self.server = HTTPServer(('localhost', 0), self.request_handler)
self.server = HTTPServer(('localhost', 0), self.request_handler,
**self.server_kwargs)

@vadmium vadmium Jun 22, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to only be testing the undocumented or internal HTTPServer parameter. It would be good to test the new documented SimpleHTTPRequestHandler parameter instead or as well.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@aisipos aisipos Jul 10, 2025

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed server_kwargs in the latest updates, and updated the tests. The only external change now is response_headers as an instance arg to SimpleHTTPRequestHandler

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
aisipos added 4 commits July 6, 2025 10:48
@aisipos
pythongh-135056: Remove --cors opt from http.server in favor of --header
a3243fe
@aisipos
pythongh-135056: Use response_headers only in SimpleHTTPRequestHandler
b1026d2
@aisipos
pythongh-135056: Add test for http.server cli --header argument
6f88c13
@aisipos
pythongh-135056: Support multiple headers of the same name.
7a793f2
@aisipos
aisipos requested a review from vadmium July 10, 2025 07:22
@aisipos

aisipos commented May 2, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

@hugovk Sorry to ask again, I think we restarted the tests before the Canonical outage ended. All the Ubuntu tests failed again with PPA problems. Would you mind running the tests again?

Looks like it might still be down, Canonical is under a massive attack. I guess I'll keep an eye on the situation and reach out once things are ready again.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@hugovk
Merge branch 'main' into https-server-cors-issue-135056
c1ab0ce
@hugovk

hugovk commented May 2, 2026

Copy link
Copy Markdown
Member

I've merged in main to include this workaround: #149248.

aisipos reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aisipos

aisipos commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

@picnixz OK, all tests are passing now. The new test test_extra_response_headers_concurrent_requests tests that the headers are correct in the case of concurrent requests, although I suspect it's not testing everything you're concerned about. Still, it's very close to the merge deadline for the 3.15 beta - would be good to get this merged shortly if you agree.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

picnixz
picnixz approved these changes May 2, 2026
View reviewed changes

@picnixz picnixz left a comment •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the tests. I don't remember if I asked but:

  • L797: we are not sending additional headers for MOVED_PERMANENTLY
  • L847: neither are we for NOT_MODIFIED

I don't think it's important that custom headers are sent in the above cases but I wanted to note them down. I think we can merge this and then we'll just fix the issues during the beta.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/http/server.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/http/server.py Outdated
Comment on lines +562 to +563
if not _is_extra and hasattr(self, '_default_response_headers'):
self._default_response_headers.append((keyword, value))

@picnixz picnixz May 2, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we consider using not hasattr(...) check as for _headers_buffer? it's mostly for a follow-up/refactoring. If we go that path, we would remove the _default_response_headers = [] in handle() and put it in flush_headers() instead, right? It would re-construct the default_response_headers for each request but this also mean that if a request does (in the future) send_header(..., is_extra=True), that is_extra is "local" to the current request and won't pollute next requests. For now it doesn't matter though but I'll write it here to remember.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@aisipos aisipos May 2, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually didn't look at the pattern used for _headers_buffer. For consistency and correctness, yes it does seem like the right thing to do it that way. I've made that change in 597b973.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@picnixz
Update Lib/http/server.py
69e59e9
picnixz
picnixz reviewed May 2, 2026
View reviewed changes

@picnixz picnixz left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor comment on the test because threaded stuff can fail badly on buildbots. But we can address it later.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_httpservers.py Outdated
Comment on lines +980 to +982
server_thread = threading.Thread(
target=threaded_server.serve_forever, args=(0.05,), daemon=True
)

@picnixz picnixz May 2, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, maybe this can hang. I don't know if this test was written as for other tests, but this may hang in some build bots. The server_thread.join call below should be added as a finalizer just in case. And we should have a short timeout before aborting the thread.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@aisipos aisipos May 2, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I added some addCleanup calls in c40f8b1 to help prevent a hang. If you think there's still a risk of the test hanging, I can just remove the test for now until we come up with a better idea.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@aisipos aisipos May 3, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still saw some resource leaking, so I just ended up removing test_extra_response_headers_concurrent_requests in 347b968 . We can add a more robust test later if need be, but I didn't want to leave a flaky test in that risked breaking.

After that checkin, there was still an env changed leakage in a windows build. I refactored a different test test_extra_response_headers_arg in a249eea to not create a server and thus also less likely to leak. After that checkin, all tests are passing.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
aisipos added 4 commits May 2, 2026 16:53
@aisipos
pythongh-135056: Add addCleanup calls to ensure test server thread ex…
c40f8b1
…its.
@aisipos
pythongh-135056: Refactor _default_reponse_headers usage.
597b973
@aisipos
pythongh-135056: Remove test_extra_response_headers_concurrent_requests
347b968
@aisipos
pythongh-135956: Help prevent leaks in test_extra_response_headers_arg
a249eea
@aisipos

aisipos commented May 3, 2026

Copy link
Copy Markdown
Contributor Author

@hugovk @picnixz Thanks everyone for the help. OK, after adjusting the tests a little in the last commits all tests are passing (and not leaking) again. Is there anything left to do, or is this PR now ready to merge?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@picnixz

picnixz commented May 3, 2026

Copy link
Copy Markdown
Member

I will run tje build bots to see if tests are hangijg somehoe ans then I will merge. Come back in a few hours to check but do not commit anything or update the branch meanwhile

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@picnixz picnixz added the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label May 3, 2026
@bedevere-bot

bedevere-bot commented May 3, 2026

Copy link
Copy Markdown

🤖 New build scheduled with the buildbot fleet by @picnixz for commit a249eea 🤖

Results will be shown at:

https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F135057%2Fmerge

If you want to schedule another build, you need to add the 🔨 test-with-buildbots label again.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-bot bedevere-bot removed the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label May 3, 2026
@picnixz

picnixz commented May 3, 2026

Copy link
Copy Markdown
Member

Ok, so we still have some file leakge but I don't think it's coming from you in particular. We can fix this is in a follow-up. Other failures are unrelated.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@picnixz
picnixz merged commit 836fbda into python:main May 3, 2026
103 of 119 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the awaiting merge label May 3, 2026
@hugovk

hugovk commented May 3, 2026

Copy link
Copy Markdown
Member

@aisipos Thank you for your contribution!

aisipos reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@picnixz

picnixz commented May 3, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Thank you for the PR! It was not straightforward, so thank you for your patience! We will fix bugs or other incompatibilities during the beta (but for that we need people testing the interface)

hugovk reacted with hooray emoji aisipos reacted with heart emoji hugovk reacted with rocket emoji
All reactions
  • 🎉 1 reaction
  • ❤️ 1 reaction
  • 🚀 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-bot

bedevere-bot commented May 3, 2026

Copy link
Copy Markdown

⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️

Hi! The buildbot AMD64 Windows PGO Tailcall 3.x (tier-1) has failed when building commit 836fbda.

What do you need to do:

  1. Don't panic.
  2. Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
  3. Go to the page of the buildbot that failed (https://buildbot.python.org/#/builders/1870/builds/544) and take a look at the build logs.
  4. Check if the failure is related to this commit (836fbda) or if it is a false positive.
  5. If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.

You can take a look at the buildbot page here:

https://buildbot.python.org/#/builders/1870/builds/544

Summary of the results of the build (if available):

==

Click to see traceback logs
remote: Enumerating objects: 32, done.        
remote: Counting objects:   3% (1/32)        
remote: Counting objects:   6% (2/32)        
remote: Counting objects:   9% (3/32)        
remote: Counting objects:  12% (4/32)        
remote: Counting objects:  15% (5/32)        
remote: Counting objects:  18% (6/32)        
remote: Counting objects:  21% (7/32)        
remote: Counting objects:  25% (8/32)        
remote: Counting objects:  28% (9/32)        
remote: Counting objects:  31% (10/32)        
remote: Counting objects:  34% (11/32)        
remote: Counting objects:  37% (12/32)        
remote: Counting objects:  40% (13/32)        
remote: Counting objects:  43% (14/32)        
remote: Counting objects:  46% (15/32)        
remote: Counting objects:  50% (16/32)        
remote: Counting objects:  53% (17/32)        
remote: Counting objects:  56% (18/32)        
remote: Counting objects:  59% (19/32)        
remote: Counting objects:  62% (20/32)        
remote: Counting objects:  65% (21/32)        
remote: Counting objects:  68% (22/32)        
remote: Counting objects:  71% (23/32)        
remote: Counting objects:  75% (24/32)        
remote: Counting objects:  78% (25/32)        
remote: Counting objects:  81% (26/32)        
remote: Counting objects:  84% (27/32)        
remote: Counting objects:  87% (28/32)        
remote: Counting objects:  90% (29/32)        
remote: Counting objects:  93% (30/32)        
remote: Counting objects:  96% (31/32)        
remote: Counting objects: 100% (32/32)        
remote: Counting objects: 100% (32/32), done.        
remote: Compressing objects:   5% (1/17)        
remote: Compressing objects:  11% (2/17)        
remote: Compressing objects:  17% (3/17)        
remote: Compressing objects:  23% (4/17)        
remote: Compressing objects:  29% (5/17)        
remote: Compressing objects:  35% (6/17)        
remote: Compressing objects:  41% (7/17)        
remote: Compressing objects:  47% (8/17)        
remote: Compressing objects:  52% (9/17)        
remote: Compressing objects:  58% (10/17)        
remote: Compressing objects:  64% (11/17)        
remote: Compressing objects:  70% (12/17)        
remote: Compressing objects:  76% (13/17)        
remote: Compressing objects:  82% (14/17)        
remote: Compressing objects:  88% (15/17)        
remote: Compressing objects:  94% (16/17)        
remote: Compressing objects: 100% (17/17)        
remote: Compressing objects: 100% (17/17), done.        
remote: Total 17 (delta 15), reused 2 (delta 0), pack-reused 0 (from 0)        
From https://github.com/python/cpython
 * branch                    main       -> FETCH_HEAD
Note: switching to '836fbdaaf32c355c7e8fb0af69f78fbbb28af8b1'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 836fbdaaf32 gh-135056: Add a `--header` CLI option to `http.server` (#135057)
Switched to and reset branch 'main'

Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\PCbuild\*.pgc
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\Lib\*.pyc
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\PCbuild\*.pgc
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\Lib\*.pyc
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\Lib\*.pyc
The system cannot find the file specified.
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\PCbuild\python*.zip
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\PCbuild\*.pgc
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\Lib\*.pyc

Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\PCbuild\python*.zip
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-bot

bedevere-bot commented May 3, 2026

Copy link
Copy Markdown

⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️

Hi! The buildbot AMD64 Windows PGO Tailcall 3.x (tier-1) has failed when building commit 836fbda.

What do you need to do:

  1. Don't panic.
  2. Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
  3. Go to the page of the buildbot that failed (https://buildbot.python.org/#/builders/1870/builds/545) and take a look at the build logs.
  4. Check if the failure is related to this commit (836fbda) or if it is a false positive.
  5. If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.

You can take a look at the buildbot page here:

https://buildbot.python.org/#/builders/1870/builds/545

Summary of the results of the build (if available):

==

Click to see traceback logs
Note: switching to '836fbdaaf32c355c7e8fb0af69f78fbbb28af8b1'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 836fbdaaf32 gh-135056: Add a `--header` CLI option to `http.server` (#135057)
Switched to and reset branch 'main'

Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\PCbuild\*.pgc
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\Lib\*.pyc
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\PCbuild\*.pgc
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\Lib\*.pyc
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\Lib\*.pyc
The system cannot find the file specified.
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\PCbuild\python*.zip
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\PCbuild\*.pgc
Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\Lib\*.pyc

Could Not Find C:\bbarea\3.x.itamaro-win64-srv-22-aws.tailcall.pgo\build\PCbuild\python*.zip
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@hugovk

hugovk commented May 3, 2026

Copy link
Copy Markdown
Member

Let's fix these, they're tier 1 and will block the 3.15 beta :)

Couple of ideas. Adjust order in teardown:

diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -576,11 +576,12 @@ class SimpleHTTPServerTestCase(BaseTestCase):
     def tearDown(self):
         try:
             os.chdir(self.cwd)
-            try:
-                shutil.rmtree(self.tempdir)
-            except:
-                pass
         finally:
             super().tearDown()
+        try:
+            shutil.rmtree(self.tempdir)
+        except:
+            pass

Or block until body is fully read:

diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -924,6 +924,7 @@ class SimpleHTTPServerTestCase(BaseTestCase):
             with open(os.path.join(self.tempdir_name, 'index.html'), 'wb') as f:
                 f.write(data)
             response = self.request(self.base_url + '/')
+            response.read()
             self.assertEqual(response.status, 200)
             self.assertEqual(response.getheader("Set-Cookie"),
                                                 'test1=value1, test2=value2')
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aisipos

aisipos commented May 3, 2026

Copy link
Copy Markdown
Contributor Author

@hugovk Is the proper procedure now to open a new PR to fix these test failures? I can do so, but won't be near a computer until about 12 hours from now. I know we're right near the beta deadline. So sorry for the trouble. It's also a bit of guesswork for me since these failures seem to happen only Windows and I only have MacOS and Linux to test on at home, so I have to make commits and wait for CI tests to see if my changes work or not.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@hugovk

hugovk commented May 3, 2026

Copy link
Copy Markdown
Member

No problem, I'll check with @picnixz and one of us can open a PR.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@hugovk hugovk mentioned this pull request May 3, 2026
gh-135056: Fix teardown order for Windows in test_httpservers #149320
Merged
@hugovk

hugovk commented May 3, 2026

Copy link
Copy Markdown
Member

Please see PR #149320.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced May 8, 2026
Python 3.15: sort allowlists, more small updates python/typeshed#15714
Merged
Add Python 3.15 path HTTP and importlib updates python/typeshed#15737
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@picnixz picnixz picnixz approved these changes
@hugovk hugovk hugovk approved these changes
@vadmium vadmium Awaiting requested review from vadmium
@AA-Turner AA-Turner Awaiting requested review from AA-Turner AA-Turner is a code owner

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

8 participants

@aisipos @donbarbos @Zheaoli @hugovk @picnixz @sethmlarson @bedevere-bot @vadmium
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.