From: Max Carrara <m.carrara@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v2 http-server 3/4] fix #4494: anyevent: redirect HTTP to HTTPS
Date: Fri, 3 Mar 2023 18:29:50 +0100 [thread overview]
Message-ID: <20230303172951.197711-4-m.carrara@proxmox.com> (raw)
In-Reply-To: <20230303172951.197711-1-m.carrara@proxmox.com>
Allow HTTP connections up until the request's header has been
parsed and processed. If no TLS handshake has been completed
beforehand, the server now responds with either a
'301 Moved Permanently' or a '308 Permanent Redirect' as noted in the
MDN web docs[1].
This is done after the header was parsed; for the redirect to work,
the `Host` header field of the request is used to create the
`Location` field of the response. This makes redirections independent
of how the server is accessed (e.g. via IP, localhost, FQDN, ...)
possible.
Upon redirection the client is immediately disconnected; otherwise,
they would have to wait for the connection to time out until
they may reconnect via TLS again.
[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/301
Signed-off-by: Max Carrara <m.carrara@proxmox.com>
---
src/PVE/APIServer/AnyEvent.pm | 46 +++++++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/src/PVE/APIServer/AnyEvent.pm b/src/PVE/APIServer/AnyEvent.pm
index 636502b..d1bba3c 100644
--- a/src/PVE/APIServer/AnyEvent.pm
+++ b/src/PVE/APIServer/AnyEvent.pm
@@ -1318,7 +1318,7 @@ sub unshift_read_header {
if $state->{key};
$self->process_header($reqstate) or return;
- # header processing complete - authenticate now
+ $self->ensure_tls_connection($reqstate) or return;
$self->authenticate_and_handle_request($reqstate) or return;
} elsif ($line =~ /^([^:\s]+)\s*:\s*(.*)/) {
@@ -1388,6 +1388,43 @@ sub process_header {
return 1;
}
+sub ensure_tls_connection {
+ my ($self, $reqstate) = @_;
+
+ # Skip if server doesn't use TLS
+ if (!$self->{tls_ctx}) {
+ return 1;
+ }
+
+ # TLS session exists, so the handshake has succeeded
+ if ($reqstate->{hdl}->{tls}) {
+ return 1;
+ }
+
+ my $request = $reqstate->{request};
+ my $method = $request->method();
+
+ my $h_host = $reqstate->{request}->header('Host');
+
+ die "Header field 'Host' not found in request\n"
+ if !$h_host;
+
+ my $secure_host = "https://" . ($h_host =~ s/^http(s)?:\/\///r);
+
+ my $header = HTTP::Headers->new('Location' => $secure_host . $request->uri());
+
+ if ($method eq 'GET' || $method eq 'HEAD') {
+ $self->error($reqstate, 301, 'Moved Permanently', $header);
+ } else {
+ $self->error($reqstate, 308, 'Permanent Redirect', $header);
+ }
+
+ # disconnect the client so they may immediately connect again via HTTPS
+ $self->client_do_disconnect($reqstate);
+
+ return;
+}
+
sub authenticate_and_handle_request {
my ($self, $reqstate) = @_;
@@ -1795,11 +1832,16 @@ sub accept_connections {
};
if (my $err = $@) { syslog('err', "$err"); }
},
- ($self->{tls_ctx} ? (tls => "accept", tls_ctx => $self->{tls_ctx}) : ()));
+ );
$handle_creation = 0;
$self->dprint("ACCEPT FH" . $clientfh->fileno() . " CONN$self->{conn_count}");
+ if ($self->{tls_ctx}) {
+ $self->dprint("Setting TLS to autostart");
+ $reqstate->{hdl}->unshift_read(tls_autostart => $self->{tls_ctx}, "accept");
+ }
+
$self->push_request_header($reqstate);
}
};
--
2.30.2
next prev parent reply other threads:[~2023-03-03 17:30 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-03 17:29 [pve-devel] [PATCH v2 http-server 0/4] refactor HTTP request processing Max Carrara
2023-03-03 17:29 ` [pve-devel] [PATCH v2 http-server 1/4] anyevent: move header processing into separate subroutine Max Carrara
2023-03-03 17:29 ` [pve-devel] [PATCH v2 http-server 2/4] anyevent: move auth and request handling " Max Carrara
2023-03-03 17:29 ` Max Carrara [this message]
2023-03-03 17:29 ` [pve-devel] [PATCH v2 http-server 4/4] anyevent: fix whitespace Max Carrara
2023-03-07 10:20 ` [pve-devel] applied series: [PATCH v2 http-server 0/4] refactor HTTP request processing Fabian Grünbichler
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230303172951.197711-4-m.carrara@proxmox.com \
--to=m.carrara@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox