Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 136 additions & 13 deletions plugins/out_s3/s3.c
Original file line number Diff line number Diff line change
Expand Up @@ -2205,6 +2205,84 @@ static int blob_request_pre_signed_url(struct flb_s3 *context,
return ret;
}

int s3_parse_presigned_url(struct flb_s3 *ctx, const char *url,
flb_sds_t *out_host, flb_sds_t *out_uri,
int *out_port)
{
int ret;
char *scheme = NULL;
char *host = NULL;
char *port = NULL;
char *uri = NULL;
int resolved_port = 0;
flb_sds_t host_sds = NULL;
flb_sds_t uri_sds = NULL;

if (out_host == NULL || out_uri == NULL || url == NULL) {
return -1;
}

ret = flb_utils_url_split(url, &scheme, &host, &port, &uri);
if (ret == -1 || host == NULL || uri == NULL) {
flb_plg_error(ctx->ins, "Invalid pre signed URL: %s", url ? url : "(null)");
goto error;
}

if (port != NULL) {
resolved_port = (int) strtoul(port, NULL, 10);
}
else if (scheme != NULL) {
if (strcasecmp(scheme, "https") == 0) {
resolved_port = 443;
}
else {
resolved_port = 80;
}
}

host_sds = flb_sds_create(host);
if (host_sds == NULL) {
goto error;
}

uri_sds = flb_sds_create(uri);
if (uri_sds == NULL) {
flb_sds_destroy(host_sds);
host_sds = NULL;
goto error;
}

if (out_port != NULL) {
*out_port = resolved_port;
}

*out_host = host_sds;
*out_uri = uri_sds;

flb_free(scheme);
flb_free(host);
flb_free(port);
flb_free(uri);

return 0;

error:
if (scheme) {
flb_free(scheme);
}
if (host) {
flb_free(host);
}
if (port) {
flb_free(port);
}
if (uri) {
flb_free(uri);
}

return -1;
}

static int blob_fetch_pre_signed_url(struct flb_s3 *context,
flb_sds_t *result_url,
char *format,
Expand Down Expand Up @@ -2383,7 +2461,7 @@ static int blob_fetch_multipart_abort_pre_signed_url(struct flb_s3 *context,

return blob_fetch_pre_signed_url(context,
result_url,
"/multipart_upload_presigned_url/%s/%s/%s/%s",
"/multipart_abort_presigned_url/%s/%s/%s/%s",
bucket,
tag,
valid_path,
Expand Down Expand Up @@ -2467,8 +2545,15 @@ static int put_blob_object(struct flb_s3 *ctx,
int ret;
int num_headers = 0;
char *final_key;
flb_sds_t uri;
flb_sds_t uri = NULL;
flb_sds_t tmp;
flb_sds_t presigned_full = NULL;
flb_sds_t presigned_host = NULL;
const char *original_host = NULL;
char *original_upstream_host = NULL;
int original_upstream_port = 0;
int original_upstream_flags = 0;
int presigned_port = 0;
char final_body_md5[25];

if (ctx->authorization_endpoint_url == NULL) {
Expand Down Expand Up @@ -2499,13 +2584,40 @@ static int put_blob_object(struct flb_s3 *ctx,
uri = tmp;
}
else {
uri = NULL;
ret = blob_fetch_put_object_pre_signed_url(ctx, &presigned_full, (char *) tag, ctx->bucket, (char *) path);

ret = blob_fetch_put_object_pre_signed_url(ctx, &uri, (char *) tag, ctx->bucket, (char *) path);
if (ret != 0) {
return -1;
}

ret = s3_parse_presigned_url(ctx, presigned_full, &presigned_host, &uri, &presigned_port);
flb_sds_destroy(presigned_full);
presigned_full = NULL;

if (ret != 0) {
return -1;
}

/* When using authorization_endpoint_url, the presigned URL may use a different port */
if (presigned_port != 0 && presigned_port != ctx->port) {
flb_plg_debug(ctx->ins, "Pre signed URL uses port %d (configured: %d)", presigned_port, ctx->port);
}

original_host = ctx->s3_client->host;
original_upstream_host = ctx->s3_client->upstream->tcp_host;
original_upstream_port = ctx->s3_client->upstream->tcp_port;
original_upstream_flags = ctx->s3_client->upstream->base.flags;
ctx->s3_client->host = presigned_host;
ctx->s3_client->upstream->tcp_host = presigned_host;
ctx->s3_client->upstream->tcp_port = presigned_port != 0 ? presigned_port : ctx->port;

/* Disable TLS for HTTP (port 80), enable for HTTPS (port 443) */
if (presigned_port == 80) {
ctx->s3_client->upstream->base.flags &= ~FLB_IO_TLS;
Comment on lines +2614 to +2616
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Disable TLS based on scheme, not only port 80

The presigned URL path switches the upstream host/port, but TLS is only disabled when presigned_port == 80. If the authorization endpoint returns an HTTP URL on a non‑80 port (e.g., http://...:8080/...), s3_parse_presigned_url will set presigned_port to 8080 and the original FLB_IO_TLS flag remains enabled. That causes a TLS handshake against a plain‑HTTP endpoint, so uploads fail in that configuration. This logic is new with the presigned URL host/port handling and should instead key TLS on the URL scheme (or explicitly disable TLS for any non‑HTTPS scheme), not just port 80.

Useful? React with 👍 / 👎.

}
Comment on lines +2614 to +2617
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Enable TLS when presigned URL requires HTTPS

The new presigned-host switch only clears TLS when the parsed port is 80, but it never re-enables TLS for HTTPS URLs. If authorization_endpoint_url is HTTP (so the original upstream flags have TLS disabled) and the presigned URL is HTTPS (e.g., https://... on 443 or another port), the client will keep TLS off and attempt a plain HTTP request to an HTTPS endpoint, which fails. The same mismatch happens for HTTP presigned URLs on non-80 ports (TLS stays enabled). Consider explicitly setting FLB_IO_TLS based on the URL scheme (or port) rather than only clearing it for port 80.

Useful? React with 👍 / 👎.


/* Disable keepalive to force new connection to the new host */
ctx->s3_client->upstream->base.flags &= ~FLB_IO_TCP_KA;
}

memset(final_body_md5, 0, sizeof(final_body_md5));
Expand All @@ -2514,8 +2626,8 @@ static int put_blob_object(struct flb_s3 *ctx,
final_body_md5, sizeof(final_body_md5));
if (ret != 0) {
flb_plg_error(ctx->ins, "Failed to create Content-MD5 header");
flb_sds_destroy(uri);
return -1;
ret = -1;
goto cleanup;
}
}

Expand All @@ -2527,8 +2639,7 @@ static int put_blob_object(struct flb_s3 *ctx,
ret = create_headers(ctx, final_body_md5, &headers, &num_headers, FLB_FALSE);
if (ret == -1) {
flb_plg_error(ctx->ins, "Failed to create headers");
flb_sds_destroy(uri);
return -1;
goto cleanup;
}

c = s3_client->client_vtable->request(s3_client, FLB_HTTP_PUT,
Expand All @@ -2545,10 +2656,9 @@ static int put_blob_object(struct flb_s3 *ctx,
*/
final_key = uri + strlen(ctx->bucket) + 1;
flb_plg_info(ctx->ins, "Successfully uploaded object %s", final_key);
flb_sds_destroy(uri);
flb_http_client_destroy(c);

return 0;
ret = 0;
goto cleanup;
}
flb_aws_print_xml_error(c->resp.payload, c->resp.payload_size,
"PutObject", ctx->ins);
Expand All @@ -2559,9 +2669,22 @@ static int put_blob_object(struct flb_s3 *ctx,
}

flb_plg_error(ctx->ins, "PutObject request failed");
flb_sds_destroy(uri);
ret = -1;

return -1;
cleanup:
if (original_host != NULL) {
ctx->s3_client->host = original_host;
ctx->s3_client->upstream->tcp_host = original_upstream_host;
ctx->s3_client->upstream->tcp_port = original_upstream_port;
ctx->s3_client->upstream->base.flags = original_upstream_flags;
flb_sds_destroy(presigned_host);
}

if (uri != NULL) {
flb_sds_destroy(uri);
}

return ret;
}

static int abort_blob_upload(struct flb_s3 *ctx,
Expand Down
4 changes: 4 additions & 0 deletions plugins/out_s3/s3.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ void multipart_upload_destroy(struct multipart_upload *m_upload);
struct flb_http_client *mock_s3_call(char *error_env_var, char *api);
int s3_plugin_under_test();

int s3_parse_presigned_url(struct flb_s3 *ctx, const char *url,
flb_sds_t *out_host, flb_sds_t *out_uri,
int *out_port);

int get_md5_base64(char *buf, size_t buf_size, char *md5_str, size_t md5_str_size);

int create_headers(struct flb_s3 *ctx, char *body_md5,
Expand Down
Loading
Loading