1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 /* Fluent Bit
4 * ==========
5 * Copyright (C) 2019-2021 The Fluent Bit Authors
6 * Copyright (C) 2015-2018 Treasure Data Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 #include <fluent-bit/flb_output_plugin.h>
22
23 #include "stackdriver.h"
24 #include "stackdriver_helper.h"
25 #include "stackdriver_timestamp.h"
26 #include <fluent-bit/flb_regex.h>
27
28 #include <ctype.h>
29
is_integer(char * str,int size)30 static int is_integer(char *str, int size) {
31 int i;
32 for (i = 0; i < size; ++ i) {
33 if (!isdigit(str[i])) {
34 return FLB_FALSE;
35 }
36 }
37 return FLB_TRUE;
38 }
39
try_assign_time(long long seconds,long long nanos,struct flb_time * tms)40 static void try_assign_time(long long seconds, long long nanos,
41 struct flb_time *tms)
42 {
43 if (seconds != 0) {
44 tms->tm.tv_sec = seconds;
45 tms->tm.tv_nsec = nanos;
46 }
47 }
48
get_integer(msgpack_object obj)49 static long long get_integer(msgpack_object obj)
50 {
51 char tmp[32];
52
53 if (obj.type == MSGPACK_OBJECT_POSITIVE_INTEGER) {
54 return obj.via.i64;
55 }
56 else if (obj.type == MSGPACK_OBJECT_STR
57 && is_integer((char *) obj.via.str.ptr,
58 obj.via.str.size)) {
59
60 /*
61 * use an intermediary buffer to perform the conversion to avoid any
62 * overflow by atoll. LLONG_MAX value is +9,223,372,036,854,775,807,
63 * so using a 32 bytes buffer is enough.
64 */
65 if (obj.via.str.size > sizeof(tmp) - 1) {
66 return 0;
67 }
68
69 memcpy(tmp, obj.via.str.ptr, obj.via.str.size);
70 tmp[obj.via.str.size] = '\0';
71
72 return atoll(tmp);
73 }
74
75 return 0;
76 }
77
extract_format_timestamp_object(msgpack_object * obj,struct flb_time * tms)78 static int extract_format_timestamp_object(msgpack_object *obj,
79 struct flb_time *tms)
80 {
81 int seconds_found = FLB_FALSE;
82 int nanos_found = FLB_FALSE;
83 long long seconds = 0;
84 long long nanos = 0;
85
86 msgpack_object_kv *p;
87 msgpack_object_kv *pend;
88 msgpack_object_kv *tmp_p;
89 msgpack_object_kv *tmp_pend;
90
91 if (obj->via.map.size == 0) {
92 return FLB_FALSE;
93 }
94 p = obj->via.map.ptr;
95 pend = obj->via.map.ptr + obj->via.map.size;
96
97 for (; p < pend; ++p) {
98 if (!validate_key(p->key, "timestamp", 9)
99 || p->val.type != MSGPACK_OBJECT_MAP) {
100 continue;
101 }
102
103 tmp_p = p->val.via.map.ptr;
104 tmp_pend = p->val.via.map.ptr + p->val.via.map.size;
105
106 for (; tmp_p < tmp_pend; ++tmp_p) {
107 if (validate_key(tmp_p->key, "seconds", 7)) {
108 seconds_found = FLB_TRUE;
109 seconds = get_integer(tmp_p->val);
110
111 if (nanos_found == FLB_TRUE) {
112 try_assign_time(seconds, nanos, tms);
113 return FLB_TRUE;
114 }
115 }
116 else if (validate_key(tmp_p->key, "nanos", 5)) {
117 nanos_found = FLB_TRUE;
118 nanos = get_integer(tmp_p->val);
119
120 if (seconds_found == FLB_TRUE) {
121 try_assign_time(seconds, nanos, tms);
122 return FLB_TRUE;
123 }
124 }
125 }
126 }
127 return FLB_FALSE;
128 }
129
extract_format_timestamp_duo_fields(msgpack_object * obj,struct flb_time * tms)130 static int extract_format_timestamp_duo_fields(msgpack_object *obj,
131 struct flb_time *tms)
132 {
133 int seconds_found = FLB_FALSE;
134 int nanos_found = FLB_FALSE;
135 long long seconds = 0;
136 long long nanos = 0;
137
138 msgpack_object_kv *p;
139 msgpack_object_kv *pend;
140
141 if (obj->via.map.size == 0) {
142 return FLB_FALSE;
143 }
144 p = obj->via.map.ptr;
145 pend = obj->via.map.ptr + obj->via.map.size;
146
147 for (; p < pend; ++p) {
148 if (validate_key(p->key, "timestampSeconds", 16)) {
149 seconds_found = FLB_TRUE;
150 seconds = get_integer(p->val);
151
152 if (nanos_found == FLB_TRUE) {
153 try_assign_time(seconds, nanos, tms);
154 return FLB_TRUE;
155 }
156 }
157 else if (validate_key(p->key, "timestampNanos", 14)) {
158 nanos_found = FLB_TRUE;
159 nanos = get_integer(p->val);
160
161 if (seconds_found == FLB_TRUE) {
162 try_assign_time(seconds, nanos, tms);
163 return FLB_TRUE;
164 }
165 }
166 }
167
168 return FLB_FALSE;
169 }
170
extract_timestamp(msgpack_object * obj,struct flb_time * tms)171 timestamp_status extract_timestamp(msgpack_object *obj,
172 struct flb_time *tms)
173 {
174 if (extract_format_timestamp_object(obj, tms)) {
175 return FORMAT_TIMESTAMP_OBJECT;
176 }
177 if (extract_format_timestamp_duo_fields(obj, tms)) {
178 return FORMAT_TIMESTAMP_DUO_FIELDS;
179 }
180 return TIMESTAMP_NOT_PRESENT;
181 }
182