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