Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 7, 2025

Adds a complete HTTPS server example demonstrating TLS integration with s3s.

Changes

  • New example crates/s3s/examples/https.rs: Shows how to run an S3 service over HTTPS using tokio-rustls

    • Loads TLS certificates and private keys from PEM files using idiomatic &Path parameters
    • Supports PKCS8, PKCS1, and SEC1 private key formats with efficient single-pass PEM parsing using rustls_pemfile::read_one()
    • Command-line arguments for certificate and key paths, host, and port
    • TLS 1.2/1.3 support with HTTP/2 and HTTP/1.1 ALPN
    • Graceful shutdown handling
    • Integration with s3s authentication
  • Dependencies: Added tokio-rustls, rustls-pemfile, clap, hyper-util, and tracing-subscriber to dev-dependencies

Usage

# Generate test certificates using OpenSSL
openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem \
    -days 365 -subj "/CN=localhost"

# Run the example
cargo run --example https -- --cert cert.pem --key key.pem
# Server listens on https://127.0.0.1:8014

The example demonstrates loading existing TLS certificates from files, which is the recommended approach for production deployments. Documentation includes commands for generating test certificates using OpenSSL.

Original prompt

This section details on the original issue you should resolve

<issue_title>HTTPS example</issue_title>
<issue_description></issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Add HTTPS example for demonstration Add HTTPS example with TLS support Dec 7, 2025
Copilot AI requested a review from Nugine December 7, 2025 09:06
@Nugine
Copy link
Collaborator

Nugine commented Dec 9, 2025

@copilot

  1. merge main branch
  2. Generating self-signed certificate on the fly is not a good example.
  3. Add support for reading existing certificate.

Copy link
Contributor Author

Copilot AI commented Dec 9, 2025

@copilot

  1. merge main branch
  2. Generating self-signed certificate on the fly is not a good example.
    ...

Done! Changes made in commit 5c0d29d:

  1. ✅ Merged main branch
  2. ✅ Removed runtime certificate generation - the example now loads certificates from PEM files instead
  3. ✅ Added support for reading existing certificates via --cert and --key CLI arguments

The example now requires users to provide certificate files, with documentation showing how to generate test certificates using OpenSSL. The example supports PKCS8, PKCS1, and SEC1 private key formats.

@Nugine Nugine marked this pull request as ready for review December 9, 2025 18:02
Copilot AI review requested due to automatic review settings December 9, 2025 18:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a comprehensive HTTPS server example to demonstrate TLS integration with s3s. The example shows how to configure and run an S3-compatible service over HTTPS using tokio-rustls for TLS support.

Key Changes:

  • New HTTPS example file with full TLS certificate handling and graceful shutdown
  • Added development dependencies for TLS (tokio-rustls, rustls-pemfile), CLI parsing (clap), HTTP utilities (hyper-util), and logging (tracing-subscriber)

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 6 comments.

File Description
crates/s3s/examples/https.rs Complete HTTPS server implementation with TLS certificate loading, multiple private key format support (PKCS8/PKCS1/SEC1), CLI argument parsing, and graceful shutdown handling
crates/s3s/Cargo.toml Added dev-dependencies for TLS support, CLI parsing, HTTP utilities, and logging

}

/// Load certificates from a PEM file
fn load_certs(path: &PathBuf) -> io::Result<Vec<CertificateDer<'static>>> {
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The path parameter should be &Path instead of &PathBuf to follow Rust API design conventions. PathBuf is an owned type and passing a reference to it is unnecessary when &Path would be more idiomatic and flexible.

Copilot uses AI. Check for mistakes.
}

/// Load private key from a PEM file
fn load_private_key(path: &PathBuf) -> io::Result<PrivateKeyDer<'static>> {
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The path parameter should be &Path instead of &PathBuf to follow Rust API design conventions. PathBuf is an owned type and passing a reference to it is unnecessary when &Path would be more idiomatic and flexible.

Copilot uses AI. Check for mistakes.
}

/// Create TLS server configuration from certificate and key files
fn create_tls_config(cert_path: &PathBuf, key_path: &PathBuf) -> io::Result<ServerConfig> {
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The cert_path and key_path parameters should be &Path instead of &PathBuf to follow Rust API design conventions. PathBuf is an owned type and passing references to it is unnecessary when &Path would be more idiomatic and flexible.

Copilot uses AI. Check for mistakes.
Comment on lines 83 to 107
// Try reading as PKCS8 first, then RSA, then EC
let mut keys = rustls_pemfile::pkcs8_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;

if !keys.is_empty() {
return Ok(PrivateKeyDer::Pkcs8(keys.remove(0)));
}

// Reset reader
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut keys = rustls_pemfile::rsa_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;

if !keys.is_empty() {
return Ok(PrivateKeyDer::Pkcs1(keys.remove(0)));
}

// Reset reader
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut keys = rustls_pemfile::ec_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;

if !keys.is_empty() {
return Ok(PrivateKeyDer::Sec1(keys.remove(0)));
}

Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The file is being opened and read three times sequentially to try different key formats. Consider using rustls_pemfile::read_one() in a loop to parse all PEM items in a single pass, then filter by type. This would be more efficient and avoid multiple file operations.

Suggested change
// Try reading as PKCS8 first, then RSA, then EC
let mut keys = rustls_pemfile::pkcs8_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;
if !keys.is_empty() {
return Ok(PrivateKeyDer::Pkcs8(keys.remove(0)));
}
// Reset reader
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut keys = rustls_pemfile::rsa_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;
if !keys.is_empty() {
return Ok(PrivateKeyDer::Pkcs1(keys.remove(0)));
}
// Reset reader
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut keys = rustls_pemfile::ec_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;
if !keys.is_empty() {
return Ok(PrivateKeyDer::Sec1(keys.remove(0)));
}
use rustls_pemfile::Item;
while let Some(item) = rustls_pemfile::read_one(&mut reader)? {
match item {
Item::Pkcs8Key(key) => {
return Ok(PrivateKeyDer::Pkcs8(key));
}
Item::RsaKey(key) => {
return Ok(PrivateKeyDer::Pkcs1(key));
}
Item::EcKey(key) => {
return Ok(PrivateKeyDer::Sec1(key));
}
_ => {}
}
}

Copilot uses AI. Check for mistakes.
Comment on lines 91 to 93
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut keys = rustls_pemfile::rsa_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The file is being opened and read three times sequentially to try different key formats. Consider using rustls_pemfile::read_one() in a loop to parse all PEM items in a single pass, then filter by type. This would be more efficient and avoid multiple file operations.

Copilot uses AI. Check for mistakes.
Comment on lines 83 to 107
// Try reading as PKCS8 first, then RSA, then EC
let mut keys = rustls_pemfile::pkcs8_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;

if !keys.is_empty() {
return Ok(PrivateKeyDer::Pkcs8(keys.remove(0)));
}

// Reset reader
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut keys = rustls_pemfile::rsa_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;

if !keys.is_empty() {
return Ok(PrivateKeyDer::Pkcs1(keys.remove(0)));
}

// Reset reader
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut keys = rustls_pemfile::ec_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;

if !keys.is_empty() {
return Ok(PrivateKeyDer::Sec1(keys.remove(0)));
}

Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The file is being opened and read three times sequentially to try different key formats. Consider using rustls_pemfile::read_one() in a loop to parse all PEM items in a single pass, then filter by type. This would be more efficient and avoid multiple file operations.

Suggested change
// Try reading as PKCS8 first, then RSA, then EC
let mut keys = rustls_pemfile::pkcs8_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;
if !keys.is_empty() {
return Ok(PrivateKeyDer::Pkcs8(keys.remove(0)));
}
// Reset reader
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut keys = rustls_pemfile::rsa_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;
if !keys.is_empty() {
return Ok(PrivateKeyDer::Pkcs1(keys.remove(0)));
}
// Reset reader
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut keys = rustls_pemfile::ec_private_keys(&mut reader).collect::<Result<Vec<_>, _>>()?;
if !keys.is_empty() {
return Ok(PrivateKeyDer::Sec1(keys.remove(0)));
}
use rustls_pemfile::{Item, read_one};
loop {
match read_one(&mut reader)? {
Some(Item::Pkcs8Key(key)) => {
return Ok(PrivateKeyDer::Pkcs8(key));
}
Some(Item::RsaKey(key)) => {
return Ok(PrivateKeyDer::Pkcs1(key));
}
Some(Item::EcKey(key)) => {
return Ok(PrivateKeyDer::Sec1(key));
}
Some(_) => continue,
None => break,
}
}

Copilot uses AI. Check for mistakes.
@Nugine
Copy link
Collaborator

Nugine commented Dec 9, 2025

@copilot apply changes based on the comments in this thread

Copy link
Contributor Author

Copilot AI commented Dec 9, 2025

@copilot apply changes based on the comments in this thread

Applied all review feedback in commit 593f8b0:

  • Changed function parameters from &PathBuf to &Path (more idiomatic Rust)
  • Refactored load_private_key to use rustls_pemfile::read_one() in a loop, eliminating multiple file opens
  • Removed needless continue statement flagged by clippy

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.

@Nugine Nugine requested a review from Copilot December 14, 2025 13:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 3 changed files in this pull request and generated 1 comment.

//! cargo run --example https -- --cert cert.pem --key key.pem
//! ```
//!
//! Then you can access the server at <https://localhost:8014>. You'll need to accept
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

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

The documentation refers to "localhost:8014" but the actual default host is "127.0.0.1" (line 124). While these typically resolve to the same address, for accuracy and consistency with the actual default values in the code, consider using "127.0.0.1:8014" instead.

Suggested change
//! Then you can access the server at <https://localhost:8014>. You'll need to accept
//! Then you can access the server at <https://127.0.0.1:8014>. You'll need to accept

Copilot uses AI. Check for mistakes.
@Nugine Nugine enabled auto-merge December 14, 2025 13:35
@Nugine Nugine added this pull request to the merge queue Dec 14, 2025
Merged via the queue into main with commit 5b238ec Dec 14, 2025
18 checks passed
@Nugine Nugine deleted the copilot/add-https-example branch December 14, 2025 13:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HTTPS example

2 participants