view s3/s3_uploader.h @ 279:b3b547563ec7

Add Google connector service and agent wiki Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code. Co-authored-by: Copilot <[email protected]> Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
author MrJuneJune <me@mrjunejune.com>
date Mon, 17 Aug 2026 22:22:36 -0700
parents 83f16548ba41
children
line wrap: on
line source

#ifndef S3_UPLOADER_H
#define S3_UPLOADER_H

/**
 * S3 Uploader
 * -----------
 *
 * Generic S3 bucket uploader using AWS Signature Version 4.
 * Built on top of seobeo HTTP client.
 *
 * ## Examples
 *
 * ### 1. Upload a file from disk
 *
 * ```c
 * S3_Config config = {
 *   .access_key_id     = "AKIAIOSFODNN7EXAMPLE",
 *   .secret_access_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
 *   .region            = "us-east-1",
 *   .bucket            = "my-bucket"
 * };
 *
 * S3_Result result = S3_Upload_File(&config, "/path/to/local/file.txt", "uploads/file.txt");
 * if (result.success)
 * {
 *   printf("Uploaded successfully!\n");
 * }
 * else
 * {
 *   printf("Error: %s\n", result.error_message);
 * }
 * S3_Result_Destroy(&result);
 * ```
 *
 * ### 2. Upload raw data from memory
 *
 * ```c
 * const char *data = "Hello, S3!";
 * S3_Result result = S3_Upload_Data(&config, (const uint8 *)data, strlen(data),
 *                                   "hello.txt", "text/plain");
 * S3_Result_Destroy(&result);
 * ```
 *
 * ### 3. Upload with custom content type
 *
 * ```c
 * S3_Result result = S3_Upload_File_With_Content_Type(&config,
 *                                                      "/path/to/image.png",
 *                                                      "images/photo.png",
 *                                                      "image/png");
 * S3_Result_Destroy(&result);
 * ```
 */

#include <stddef.h>

#include "dowa/dowa.h"

// S3 configuration
typedef struct {
  const char *access_key_id;      // AWS access key ID
  const char *secret_access_key;  // AWS secret access key
  const char *region;             // AWS region (e.g., "us-east-1")
  const char *bucket;             // S3 bucket name
  const char *endpoint;           // Optional custom endpoint (NULL for default AWS)
  boolean     use_path_style;     // Use path-style URLs (bucket in path, not subdomain)
} S3_Config;

// Upload result
typedef struct {
  boolean     success;        // TRUE if upload succeeded
  int32       status_code;    // HTTP status code
  char       *error_message;  // Error message (NULL on success)
  char       *etag;           // ETag of uploaded object (on success)
  Dowa_Arena *p_arena;        // Internal arena (do not modify)
} S3_Result;

// --- Core API --- //

/* Upload file from disk to S3. Content-Type is auto-detected. */
extern S3_Result S3_Upload_File(const S3_Config *p_config,
                                const char *local_path,
                                const char *s3_key);

/* Upload file with explicit content type. */
extern S3_Result S3_Upload_File_With_Content_Type(const S3_Config *p_config,
                                                   const char *local_path,
                                                   const char *s3_key,
                                                   const char *content_type);

/* Upload raw data from memory to S3. */
extern S3_Result S3_Upload_Data(const S3_Config *p_config,
                                const uint8 *data,
                                size_t data_length,
                                const char *s3_key,
                                const char *content_type);

/* Free resources associated with result. */
extern void S3_Result_Destroy(S3_Result *p_result);

// --- Presigned URLs --- //

// Presigned URL result
typedef struct {
  boolean     success;        // TRUE if generation succeeded
  char       *url;            // The presigned URL (on success)
  char       *error_message;  // Error message (on failure)
  Dowa_Arena *p_arena;        // Internal arena (do not modify)
} S3_Presigned_URL;

/* Generate a presigned URL for uploading (PUT) a file.
 *
 * The client can use this URL to upload directly to S3 without credentials.
 *
 * Example:
 *   S3_Presigned_URL url = S3_Presign_Put(&config, "uploads/file.txt", "image/png", 3600);
 *   if (url.success) {
 *     printf("Upload URL: %s\n", url.url);
 *     // Client does: curl -X PUT -H "Content-Type: image/png" --data-binary @file.png "$URL"
 *   }
 *   S3_Presigned_URL_Destroy(&url);
 */
extern S3_Presigned_URL S3_Presign_Put(const S3_Config *p_config,
                                        const char *s3_key,
                                        const char *content_type,
                                        int32 expires_seconds);

/* Generate a presigned URL for downloading (GET) a file.
 *
 * Example:
 *   S3_Presigned_URL url = S3_Presign_Get(&config, "uploads/file.txt", 3600);
 *   if (url.success) {
 *     printf("Download URL: %s\n", url.url);
 *     // Client does: curl "$URL" -o file.txt
 *   }
 *   S3_Presigned_URL_Destroy(&url);
 */
extern S3_Presigned_URL S3_Presign_Get(const S3_Config *p_config,
                                        const char *s3_key,
                                        int32 expires_seconds);

/* Free resources associated with presigned URL result. */
extern void S3_Presigned_URL_Destroy(S3_Presigned_URL *p_url);

// --- Utility Functions --- //

/* Guess content type from file extension. Returns "application/octet-stream" if unknown. */
extern const char *S3_Guess_Content_Type(const char *filename);

#endif