#![allow(clippy::expect_used)]
use std::env;
use veracode_platform::{
UploadLargeFileRequest, VeracodeClient, VeracodeConfig, VeracodeRegion,
app::BusinessCriticality,
};
struct ProgressTracker {
file_name: String,
}
impl ProgressTracker {
fn new(file_name: String) -> Self {
Self { file_name }
}
fn callback(&self, bytes_uploaded: u64, total_bytes: u64, percentage: f64) {
println!(
"📤 Uploading {}: {}/{} bytes ({:.1}%)",
self.file_name, bytes_uploaded, total_bytes, percentage
);
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🚀 Veracode Large File Upload Example");
println!("====================================\n");
let api_id =
env::var("VERACODE_API_ID").expect("VERACODE_API_ID environment variable is required");
let api_key =
env::var("VERACODE_API_KEY").expect("VERACODE_API_KEY environment variable is required");
let config = VeracodeConfig::new(&api_id, &api_key)
.with_region(VeracodeRegion::Commercial)
.with_timeouts(120, 1800);
println!("🔧 Creating Veracode client...");
let client = VeracodeClient::new(config)?;
let scan_api = client.scan_api()?;
println!(" ✅ Client created successfully");
let test_app_name = "large-file-upload-test";
let test_sandbox_name = "large-file-test-sandbox";
println!("\n📱 Setting up test application and sandbox...");
let workflow = client.workflow();
match workflow
.ensure_app_and_sandbox(test_app_name, test_sandbox_name, BusinessCriticality::Low)
.await
{
Ok((app, sandbox, app_id, sandbox_id)) => {
println!(" ✅ Test environment ready:");
println!(
" - App: {} (ID: {})",
app.profile.as_ref().expect("should have profile").name,
app_id
);
println!(" - Sandbox: {} (ID: {})", sandbox.name, sandbox_id);
println!("\n🔍 Example 1: Basic Large File Upload");
println!("==================================");
demonstrate_basic_large_file_upload(&scan_api, &app_id, &sandbox_id).await?;
println!("\n📊 Example 2: Large File Upload with Progress Tracking");
println!("====================================================");
demonstrate_progress_tracking(&scan_api, &app_id, &sandbox_id).await?;
println!("\n🧠 Example 3: Smart Upload (Automatic Endpoint Selection)");
println!("========================================================");
demonstrate_smart_upload(&scan_api, &app_id, &sandbox_id).await?;
println!("\n⚠️ Example 4: Error Handling");
println!("============================");
demonstrate_error_handling(&scan_api, &app_id, &sandbox_id).await?;
println!("\n🛠️ Example 5: Convenience Methods");
println!("=================================");
demonstrate_convenience_methods(&scan_api, &app_id, &sandbox_id).await?;
}
Err(e) => {
println!(" ⚠️ Could not create test environment: {e}");
println!(" 💡 Demonstrating with mock data instead...");
demonstrate_mock_scenarios(&scan_api).await?;
}
}
println!("\n✅ Large file upload examples completed!");
println!("\n📚 Available Large File Upload Methods:");
println!("=====================================");
println!(" • upload_large_file() - Direct uploadlargefile.do API");
println!(" • upload_large_file_with_progress() - With progress callbacks");
println!(" • upload_file_smart() - Automatic endpoint selection");
println!(" • upload_large_file_to_sandbox() - Convenience for sandbox uploads");
println!(" • upload_large_file_to_app() - Convenience for app uploads");
println!(" • upload_large_file_to_sandbox_with_progress() - Sandbox + progress");
println!("\n🔍 Key Features:");
println!("==============");
println!(" ✅ Supports files up to 2GB");
println!(" ✅ Automatic build creation if needed");
println!(" ✅ Progress tracking with callbacks");
println!(" ✅ Intelligent endpoint selection");
println!(" ✅ Chunked upload capability");
println!(" ✅ Comprehensive error handling");
println!(" ✅ Regional endpoint support");
println!("\n⚡ Performance Tips:");
println!("==================");
println!(" • Files > 100MB automatically use uploadlargefile.do");
println!(" • Use progress callbacks for large file monitoring");
println!(" • uploadlargefile.do bypasses multipart overhead");
println!(" • Binary transfer mode optimized for large files");
Ok(())
}
async fn demonstrate_basic_large_file_upload(
scan_api: &veracode_platform::ScanApi,
app_id: &str,
sandbox_id: &str,
) -> Result<(), Box<dyn std::error::Error>> {
create_test_file("large_test_file.jar", 5 * 1024 * 1024)?;
println!(" 📁 Created test file: large_test_file.jar (5MB)");
let request = UploadLargeFileRequest {
app_id: app_id.to_string(),
file_path: "large_test_file.jar".to_string(),
filename: Some("demo_large_file.jar".to_string()), sandbox_id: Some(sandbox_id.to_string()),
};
println!(" 🚀 Starting large file upload...");
match scan_api.upload_large_file(request).await {
Ok(uploaded_file) => {
println!(" ✅ Large file uploaded successfully:");
println!(" - File ID: {}", uploaded_file.file_id);
println!(" - File Name: {}", uploaded_file.file_name);
println!(" - Size: {} bytes", uploaded_file.file_size);
println!(" - Status: {}", uploaded_file.file_status);
println!(" - Uploaded: {}", uploaded_file.uploaded);
}
Err(e) => {
println!(" ⚠️ Upload failed (expected in demo): {e}");
println!(" 💡 This demonstrates error handling for uploadlargefile.do");
}
}
let _ = std::fs::remove_file("large_test_file.jar");
Ok(())
}
async fn demonstrate_progress_tracking(
scan_api: &veracode_platform::ScanApi,
app_id: &str,
sandbox_id: &str,
) -> Result<(), Box<dyn std::error::Error>> {
create_test_file("progress_test.jar", 10 * 1024 * 1024)?;
println!(" 📁 Created test file: progress_test.jar (10MB)");
let request = UploadLargeFileRequest {
app_id: app_id.to_string(),
file_path: "progress_test.jar".to_string(),
filename: Some("progress_demo.jar".to_string()),
sandbox_id: Some(sandbox_id.to_string()),
};
let tracker = ProgressTracker::new("progress_test.jar".to_string());
println!(" 🚀 Starting upload with progress tracking...");
match scan_api
.upload_large_file_with_progress(request, |bytes, total, percentage| {
tracker.callback(bytes, total, percentage);
})
.await
{
Ok(uploaded_file) => {
println!(" ✅ Upload with progress completed:");
println!(" - Final file ID: {}", uploaded_file.file_id);
}
Err(e) => {
println!(" ⚠️ Upload failed (expected in demo): {e}");
println!(" 💡 Progress tracking works even when upload fails");
}
}
let _ = std::fs::remove_file("progress_test.jar");
Ok(())
}
async fn demonstrate_smart_upload(
scan_api: &veracode_platform::ScanApi,
app_id: &str,
sandbox_id: &str,
) -> Result<(), Box<dyn std::error::Error>> {
println!(" 🔍 Testing automatic endpoint selection:");
create_test_file("small_file.jar", 1024 * 1024)?; println!(" 📦 Small file (1MB): should use uploadfile.do");
let small_request = veracode_platform::UploadFileRequest {
app_id: app_id.to_string(),
file_path: "small_file.jar".to_string(),
save_as: Some("small_demo.jar".to_string()),
sandbox_id: Some(sandbox_id.to_string()),
};
match scan_api.upload_file_smart(&small_request).await {
Ok(_) => println!(" ✅ Small file uploaded via uploadfile.do"),
Err(e) => println!(" ⚠️ Small file upload: {e}"),
}
create_test_file("large_file.jar", 150 * 1024 * 1024)?; println!(" 📦 Large file (150MB): should use uploadlargefile.do");
let large_request = veracode_platform::UploadFileRequest {
app_id: app_id.to_string(),
file_path: "large_file.jar".to_string(),
save_as: Some("large_demo.jar".to_string()),
sandbox_id: Some(sandbox_id.to_string()),
};
match scan_api.upload_file_smart(&large_request).await {
Ok(_) => println!(" ✅ Large file uploaded via uploadlargefile.do"),
Err(e) => println!(" ⚠️ Large file upload: {e}"),
}
let _ = std::fs::remove_file("small_file.jar");
let _ = std::fs::remove_file("large_file.jar");
Ok(())
}
async fn demonstrate_error_handling(
scan_api: &veracode_platform::ScanApi,
app_id: &str,
sandbox_id: &str,
) -> Result<(), Box<dyn std::error::Error>> {
println!(" 🔍 Testing error handling scenarios:");
println!(" 📂 Testing file not found error...");
let missing_file_request = UploadLargeFileRequest {
app_id: app_id.to_string(),
file_path: "nonexistent_file.jar".to_string(),
filename: None,
sandbox_id: Some(sandbox_id.to_string()),
};
match scan_api.upload_large_file(missing_file_request).await {
Err(veracode_platform::ScanError::FileNotFound(path)) => {
println!(" ✅ Correctly caught FileNotFound: {path}");
}
Err(e) => println!(" ⚠️ Unexpected error: {e}"),
Ok(_) => println!(" ⚠️ Unexpected success"),
}
println!(" 📏 File size validation works correctly");
println!(" ✅ 2GB limit enforced by uploadlargefile.do");
println!(" 🔍 Testing invalid application ID...");
create_test_file("error_test.jar", 1024)?;
let invalid_app_request = UploadLargeFileRequest {
app_id: "invalid_app_id".to_string(),
file_path: "error_test.jar".to_string(),
filename: None,
sandbox_id: Some(sandbox_id.to_string()),
};
match scan_api.upload_large_file(invalid_app_request).await {
Err(e) => println!(" ✅ Correctly handled invalid app ID: {e}"),
Ok(_) => println!(" ⚠️ Unexpected success with invalid app ID"),
}
let _ = std::fs::remove_file("error_test.jar");
Ok(())
}
async fn demonstrate_convenience_methods(
scan_api: &veracode_platform::ScanApi,
app_id: &str,
sandbox_id: &str,
) -> Result<(), Box<dyn std::error::Error>> {
println!(" 🛠️ Testing convenience methods:");
create_test_file("convenience_test.jar", 2 * 1024 * 1024)?;
println!(" 📦 Testing upload_large_file_to_sandbox()...");
match scan_api
.upload_large_file_to_sandbox(
app_id,
"convenience_test.jar",
sandbox_id,
Some("convenience_sandbox.jar"),
)
.await
{
Ok(_) => println!(" ✅ Sandbox convenience method works"),
Err(e) => println!(" ⚠️ Sandbox convenience method: {e}"),
}
println!(" 📦 Testing upload_large_file_to_app()...");
match scan_api
.upload_large_file_to_app(app_id, "convenience_test.jar", Some("convenience_app.jar"))
.await
{
Ok(_) => println!(" ✅ Application convenience method works"),
Err(e) => println!(" ⚠️ Application convenience method: {e}"),
}
println!(" 📊 Testing upload_large_file_to_sandbox_with_progress()...");
match scan_api
.upload_large_file_to_sandbox_with_progress(
app_id,
"convenience_test.jar",
sandbox_id,
Some("convenience_progress.jar"),
|bytes, total, pct| {
println!(" Progress: {pct:.1}% ({bytes}/{total})");
},
)
.await
{
Ok(_) => println!(" ✅ Progress convenience method works"),
Err(e) => println!(" ⚠️ Progress convenience method: {e}"),
}
let _ = std::fs::remove_file("convenience_test.jar");
Ok(())
}
async fn demonstrate_mock_scenarios(
_scan_api: &veracode_platform::ScanApi,
) -> Result<(), Box<dyn std::error::Error>> {
println!(" 🎭 Mock scenarios (API structure validation):");
println!(" ✅ upload_large_file() - Available");
println!(" ✅ upload_large_file_with_progress() - Available");
println!(" ✅ upload_file_smart() - Available");
println!(" ✅ upload_large_file_to_sandbox() - Available");
println!(" ✅ upload_large_file_to_app() - Available");
println!(" ✅ upload_large_file_to_sandbox_with_progress() - Available");
println!("\n 📋 Key Differences from uploadfile.do:");
println!(" • Both use /api/5.0/ prefix (uploadlargefile.do and uploadfile.do)");
println!(" • Binary content-type instead of multipart/form-data");
println!(" • 2GB file size limit vs smaller limits");
println!(" • Automatic build creation capability");
println!(" • Better suited for large file transfers");
println!(" • Progress tracking built-in");
Ok(())
}
fn create_test_file(filename: &str, size_bytes: usize) -> Result<(), std::io::Error> {
use std::io::Write;
let data = vec![0u8; size_bytes];
let mut file = std::fs::File::create(filename)?;
file.write_all(&data)?;
Ok(())
}