summaryrefslogtreecommitdiffstats
path: root/src/fluent-bit/plugins/out_azure_blob/azure_blob_http.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fluent-bit/plugins/out_azure_blob/azure_blob_http.c')
-rw-r--r--src/fluent-bit/plugins/out_azure_blob/azure_blob_http.c361
1 files changed, 361 insertions, 0 deletions
diff --git a/src/fluent-bit/plugins/out_azure_blob/azure_blob_http.c b/src/fluent-bit/plugins/out_azure_blob/azure_blob_http.c
new file mode 100644
index 000000000..5ac81a9a1
--- /dev/null
+++ b/src/fluent-bit/plugins/out_azure_blob/azure_blob_http.c
@@ -0,0 +1,361 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Fluent Bit
+ * ==========
+ * Copyright (C) 2015-2022 The Fluent Bit Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fluent-bit/flb_output_plugin.h>
+#include <fluent-bit/flb_http_client.h>
+#include <fluent-bit/flb_base64.h>
+#include <fluent-bit/flb_crypto.h>
+#include <fluent-bit/flb_hmac.h>
+#include <fluent-bit/flb_sds.h>
+#include <fluent-bit/flb_kv.h>
+
+#include "azure_blob.h"
+#include "azure_blob_uri.h"
+
+static int hmac_sha256_sign(unsigned char out[32],
+ unsigned char *key, size_t key_len,
+ unsigned char *msg, size_t msg_len)
+{
+ return flb_hmac_simple(FLB_HASH_SHA256,
+ key, key_len,
+ msg, msg_len,
+ out, 32);
+}
+
+static flb_sds_t canonical_headers(struct flb_http_client *c)
+{
+ flb_sds_t ch;
+ flb_sds_t tmp;
+ struct flb_kv *kv;
+ struct mk_list *head;
+
+ ch = flb_sds_create_size(mk_list_size(&c->headers) * 64);
+ if (!ch) {
+ return NULL;
+ }
+
+ mk_list_foreach(head, &c->headers) {
+ kv = mk_list_entry(head, struct flb_kv, _head);
+ if (strncmp(kv->key, "x-ms-", 5) != 0) {
+ continue;
+ }
+
+ /* key */
+ tmp = flb_sds_cat(ch, kv->key, flb_sds_len(kv->key));
+ if (!tmp) {
+ flb_sds_destroy(ch);
+ return NULL;
+ }
+ ch = tmp;
+
+ /* sep */
+ tmp = flb_sds_cat(ch, ":", 1);
+ if (!tmp) {
+ flb_sds_destroy(ch);
+ return NULL;
+ }
+ ch = tmp;
+
+ /* value */
+ tmp = flb_sds_cat(ch, kv->val, flb_sds_len(kv->val));
+ if (!tmp) {
+ flb_sds_destroy(ch);
+ return NULL;
+ }
+ ch = tmp;
+
+ tmp = flb_sds_cat(ch, "\n", 1);
+ if (!tmp) {
+ flb_sds_destroy(ch);
+ return NULL;
+ }
+ ch = tmp;
+ }
+
+ return ch;
+}
+
+static flb_sds_t canonical_resource(struct flb_azure_blob *ctx,
+ struct flb_http_client *c)
+{
+ int pos;
+ int len;
+ int kv_start;
+ char *p;
+ size_t size;
+ flb_sds_t cr;
+ flb_sds_t dec_uri;
+ flb_sds_t tmp;
+
+ len = strlen(c->uri);
+ size = flb_sds_len(ctx->account_name) + len + 64;
+
+ cr = flb_sds_create_size(size);
+ if (!cr) {
+ return NULL;
+ }
+
+ dec_uri = azb_uri_decode(c->uri, len);
+ tmp = flb_sds_printf(&cr, "/%s%s", ctx->account_name, dec_uri);
+ if (!tmp) {
+ flb_sds_destroy(dec_uri);
+ flb_sds_destroy(cr);
+ return NULL;
+ }
+ flb_sds_destroy(dec_uri);
+
+ pos = 1 + flb_sds_len(ctx->account_name);
+
+ p = strchr(cr + pos, '?');
+ if (p) {
+ kv_start = FLB_TRUE;
+ while (*p) {
+ if (*p == '?') {
+ *p = '\n';
+ }
+ else if (*p == '=' && kv_start == FLB_TRUE) {
+ *p = ':';
+ kv_start = FLB_FALSE;
+ }
+ else if (*p == '&') {
+ *p = '\n';
+ kv_start = FLB_TRUE;
+ }
+ p++;
+ }
+ }
+
+ return cr;
+}
+
+flb_sds_t azb_http_canonical_request(struct flb_azure_blob *ctx,
+ struct flb_http_client *c,
+ ssize_t content_length,
+ int content_type,
+ int content_encoding)
+{
+ int ret;
+ size_t size;
+ size_t o_len = 0;
+ flb_sds_t can_req;
+ flb_sds_t can_res;
+ flb_sds_t can_headers;
+ flb_sds_t tmp = NULL;
+ char *b64 = NULL;
+ char *encoding;
+ char *ctype = "";
+ unsigned char signature[32];
+
+ size = strlen(c->uri) + (mk_list_size(&c->headers) * 64) + 256;
+ can_req = flb_sds_create_size(size);
+ if (!can_req) {
+ flb_plg_error(ctx->ins, "cannot allocate buffer for canonical request");
+ return NULL;
+ }
+
+ switch (c->method) {
+ case FLB_HTTP_GET:
+ tmp = flb_sds_cat(can_req, "GET\n", 4);
+ break;
+ case FLB_HTTP_POST:
+ tmp = flb_sds_cat(can_req, "POST\n", 5);
+ break;
+ case FLB_HTTP_PUT:
+ tmp = flb_sds_cat(can_req, "PUT\n", 4);
+ break;
+ };
+
+ if (!tmp) {
+ flb_plg_error(ctx->ins, "invalid processing HTTP method");
+ flb_sds_destroy(can_req);
+ return NULL;
+ }
+
+ if (content_encoding == AZURE_BLOB_CE_GZIP) {
+ encoding = "gzip";
+ }
+ else {
+ encoding = "";
+ }
+
+ flb_sds_printf(&can_req,
+ "%s\n" /* Content-Encoding */
+ "\n", /* Content-Language */
+ encoding
+ );
+
+ if (content_length >= 0) {
+ flb_sds_printf(&can_req,
+ "%zi\n" /* Content-Length */,
+ content_length);
+ }
+ else {
+ flb_sds_printf(&can_req,
+ "\n" /* Content-Length */
+ );
+ }
+
+ if (content_type == AZURE_BLOB_CT_NONE) {
+ ctype = "";
+ }
+ else if (content_type == AZURE_BLOB_CT_JSON) {
+ ctype = "application/json";
+ }
+ else if (content_type == AZURE_BLOB_CT_GZIP) {
+ ctype = "application/gzip";
+ }
+
+ flb_sds_printf(&can_req,
+ "\n" /* Content-MD5 */
+ "%s\n" /* Content-Type */
+ "\n" /* Date */
+ "\n" /* If-Modified-Since */
+ "\n" /* If-Match */
+ "\n" /* If-None-Match */
+ "\n" /* If-Unmodified-Since */
+ "\n" /* Range */,
+ ctype);
+
+ /* Append canonicalized headers */
+ can_headers = canonical_headers(c);
+ if (!can_headers) {
+ flb_sds_destroy(can_req);
+ return NULL;
+ }
+ tmp = flb_sds_cat(can_req, can_headers, flb_sds_len(can_headers));
+ if (!tmp) {
+ flb_sds_destroy(can_req);
+ flb_sds_destroy(can_headers);
+ return NULL;
+ }
+ can_req = tmp;
+ flb_sds_destroy(can_headers);
+
+ /* Append canonical resource */
+ can_res = canonical_resource(ctx, c);
+ if (!can_res) {
+ flb_sds_destroy(can_req);
+ return NULL;
+ }
+ tmp = flb_sds_cat(can_req, can_res, flb_sds_len(can_res));
+ if (!tmp) {
+ flb_sds_destroy(can_res);
+ flb_sds_destroy(can_req);
+ return NULL;
+ }
+ can_req = tmp;
+ flb_sds_destroy(can_res);
+
+ flb_plg_trace(ctx->ins, "string to sign\n%s", can_req);
+
+ /* Signature */
+ hmac_sha256_sign(signature, ctx->decoded_sk, ctx->decoded_sk_size,
+ (unsigned char *) can_req, flb_sds_len(can_req));
+ flb_sds_destroy(can_req);
+
+ /* base64 decoded size */
+ size = ((4 * ((sizeof(signature) + 1)) / 3) + 1);
+ b64 = flb_sds_create_size(size);
+ if (!b64) {
+ return NULL;
+ }
+
+ ret = flb_base64_encode((unsigned char *) b64, size, &o_len,
+ signature, sizeof(signature));
+ if (ret != 0) {
+ flb_sds_destroy(b64);
+ return NULL;
+ }
+ flb_sds_len_set(b64, o_len);
+
+ return b64;
+}
+
+int azb_http_client_setup(struct flb_azure_blob *ctx, struct flb_http_client *c,
+ ssize_t content_length, int blob_type,
+ int content_type, int content_encoding)
+{
+ int len;
+ time_t now;
+ struct tm tm;
+ char tmp[64];
+ flb_sds_t can_req;
+ flb_sds_t auth;
+
+ /* Header: User Agent */
+ flb_http_add_header(c, "User-Agent", 10, "Fluent-Bit", 10);
+
+ /* Header: Content-Type */
+ if (content_type == AZURE_BLOB_CT_JSON) {
+ flb_http_add_header(c,
+ AZURE_BLOB_CT, sizeof(AZURE_BLOB_CT) - 1,
+ "application/json", 16);
+ }
+ else if (content_type == AZURE_BLOB_CT_GZIP) {
+ flb_http_add_header(c,
+ AZURE_BLOB_CT, sizeof(AZURE_BLOB_CT) - 1,
+ "application/gzip", 16);
+ }
+
+ if (content_encoding == AZURE_BLOB_CE_GZIP) {
+ flb_http_add_header(c,
+ AZURE_BLOB_CE, sizeof(AZURE_BLOB_CE) - 1,
+ "gzip", 4);
+ }
+
+ /* Azure header: x-ms-blob-type */
+ if (blob_type == FLB_TRUE) {
+ if (ctx->btype == AZURE_BLOB_APPENDBLOB) {
+ flb_http_add_header(c, "x-ms-blob-type", 14, "AppendBlob", 10);
+ }
+ else if (ctx->btype == AZURE_BLOB_BLOCKBLOB) {
+ flb_http_add_header(c, "x-ms-blob-type", 14, "BlockBlob", 9);
+ }
+ }
+
+ /* Azure header: x-ms-date */
+ now = time(NULL);
+ gmtime_r(&now, &tm);
+ len = strftime(tmp, sizeof(tmp) - 1, "%a, %d %b %Y %H:%M:%S GMT", &tm);
+
+ flb_http_add_header(c, "x-ms-date", 9, tmp, len);
+
+ /* Azure header: x-ms-version */
+ flb_http_add_header(c, "x-ms-version", 12, "2019-12-12", 10);
+
+ can_req = azb_http_canonical_request(ctx, c, content_length, content_type,
+ content_encoding);
+
+ auth = flb_sds_create_size(64 + flb_sds_len(can_req));
+
+ flb_sds_cat(auth, ctx->shared_key_prefix, flb_sds_len(ctx->shared_key_prefix));
+ flb_sds_cat(auth, can_req, flb_sds_len(can_req));
+
+ /* Azure header: authorization */
+ flb_http_add_header(c, "Authorization", 13, auth, flb_sds_len(auth));
+
+ /* Release buffers */
+ flb_sds_destroy(can_req);
+ flb_sds_destroy(auth);
+
+ /* Set callback context to the HTTP client context */
+ flb_http_set_callback_context(c, ctx->ins->callback);
+
+ return 0;
+}