/* * Copyright (c) 2023 Markus Hennecke * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include "util.h" #include #define TS_PARSE_FMT "%FT%T%z" /* * Check a timestamp formed like * YYYY-MM-DDTHH:MM(:SS)?(.msec)?(+[0-9]{2}:[0-9]{2}|Z)? */ int validate_timestamp(struct kpair *_kp) { /* At least 10 characters requiered for a timestamp */ if (_kp->valsz < 10) return 0; /* Check for date only if the strlen is 10 */ if (_kp->valsz == 10) return kvalid_date(_kp); /* Between 10 and 16 characters can't be avalid timestamp */ /* Next minimal timestamp has 16 characters */ if (_kp->valsz < 16) return 0; /* Could be a timestamp with timezone, don't parse it by hand but * use strptime instead */ if (_kp->valsz >= 20) { if (_kp->valsz != strlen(_kp->val)) return 0; struct tm tm; char *parse_end = strptime(_kp->val, TS_PARSE_FMT, &tm); if (parse_end == NULL || *parse_end != '\0') return 0; fprintf(stderr, "tm_gmtoff = %ld\n", tm.tm_gmtoff); _kp->parsed.i = (int64_t )timegm(&tm) - tm.tm_gmtoff; _kp->type = KPAIR_INTEGER; return 1; } if (!isdigit(_kp->val[0]) || !isdigit(_kp->val[1]) || !isdigit(_kp->val[2]) || !isdigit(_kp->val[3]) || ('-' != _kp->val[4]) || !isdigit(_kp->val[5]) || !isdigit(_kp->val[6]) || ('-' != _kp->val[7]) || !isdigit(_kp->val[8]) || !isdigit(_kp->val[9]) || ('T' != _kp->val[10]) || !isdigit(_kp->val[11]) || !isdigit(_kp->val[12]) || (':' != _kp->val[13]) || !isdigit(_kp->val[14]) || !isdigit(_kp->val[15])) return 0; if ((_kp->valsz == 16) && ('\0' != _kp->val[16])) return 0; const int year = atoi(&_kp->val[0]); const int month = atoi(&_kp->val[5]); const int day = atoi(&_kp->val[8]); const int hour = atoi(&_kp->val[11]); const int minute = atoi(&_kp->val[14]); int seconds = 0; if (_kp->valsz >= 19) { if ((':' != _kp->val[16]) || !isdigit(_kp->val[17]) || !isdigit(_kp->val[18])) return 0; if ((_kp->valsz == 19) && ('\0' != _kp->val[19])) return 0; seconds = atoi(&_kp->val[17]); } if (! khttp_datetime2epoch(&_kp->parsed.i, day, month, year, hour, minute, seconds)) return 0; _kp->type = KPAIR_INTEGER; return 1; } /* * Check the device ID to fit into 36 characters, e.g. it is a UUID or an * ID string. */ int validate_device(struct kpair *_kp) { if (_kp->valsz > 36) return 0; // XXX change this to kvalid_stringne if it becomes mandatory return kvalid_string(_kp); } const char * parameter(struct kreq *r, const int param_idx) { return (r->fieldmap[param_idx]) ? r->fieldmap[param_idx]->val : NULL; } void response(struct kreq *r, const int status, const int content_type, const char *body) { khttp_head(r, kresps[KRESP_STATUS], "%s", khttps[status]); khttp_head(r, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[content_type]); khttp_body(r); if (body) khttp_puts(r, body); }