char *asn_replace(const char *regex, const char *rep, const char *str, mmatic *mm) { int cv[CVS], cvn, rc, br, offset = 0, len = strlen(str); xstr *xs = MMXSTR_CREATE(""); char *mem = malloc(strlen(rep) + 1), *p, *bs; while ((rc = _regex_match(regex, str, len, offset, cv, &cvn)) == 1 && cv[0] >= 0 && cv[1] >= cv[0]) { if (cv[0] >= len) break; dbg(8, "asn_replace(): matched at %d-%d (rc=%d, offset=%d)\n", cv[0], cv[1], rc, offset); /* copy text up to the first match */ xstr_append_size(xs, str+offset, cv[0]-offset); /* replace, handling backreferences */ strcpy(mem, rep); for (bs = p = mem; (bs = strchr(bs, '\\'));) { if (!bs[1] || !isdigit(bs[1])) continue; /* append everything up to \, position bs on the number */ *bs++ = '\0'; xstr_append(xs, p); /* position p on the end of the number + 1 */ for (p = bs; *p && isdigit(*p); p++); /* substitute */ br = atoi(bs); if (br++ > 0 && br <= cvn) { # define IB (2*br - 2) # define IT (2*br - 1) dbg(9, "asn_replace(): appending backreference %d between %d and %d\n", br-1, cv[IB], cv[IT]-1); xstr_append_size(xs, str + cv[IB], cv[IT] - cv[IB]); } else { dbg(1, "asn_replace(): invalid backreference: %d\n", br-1); } bs = p; } /* in no backreferences case, this appends the whole "rep" string */ xstr_append(xs, p); /* start next match after * XXX: pcreapi(3) manual page says "The first element of a pair is set to the offset of the first character in * a substring, and the second is set to the offset of the first character *after* the end of a substring.", but * does not mention that e.g. a pattern of just /$/m will return cv[1] == cv[0]! */ offset = cv[1] + (cv[1] == cv[0]); if (offset >= len) break; } if (offset <= len); xstr_append(xs, str + offset); /* may be just "" */ free(mem); return xs->s; }
__USE_LIBASN int main(int argc, char *argv[]) { char buf[BUFSIZ]; mmatic *mm = mmatic_create(); xstr *xs = xstr_create("", mm); json *js = json_create(mm); while (fgets(buf, BUFSIZ, stdin)) xstr_append(xs, buf); ut *parsed = json_parse(js, xstr_string(xs)); if (ut_ok(parsed)) printf("%s", json_print(js, parsed)); else printf("%s\n", ut_err(parsed)); return 0; }
bool read822(struct req *req) { char buf[BUFSIZ]; xstr *input = xstr_create("", req); while (fgets(buf, sizeof(buf), stdin)) { if (!buf[0] || buf[0] == '\n') break; xstr_append(input, buf); } /* eof? */ if (xstr_length(input) == 0) exit(0); dbg(8, "parsing %s\n", xstr_string(input)); req->params = ut_new_thash( rfc822_parse(xstr_string(input), req), req); return common(req, true); }
/** Parse config file * @retval 0 success * @retval 1 syntax error * @retval 2 logic error * @retval 3 other error */ static int parse_config(struct mg *mg) { FILE *fp; xstr *xs; char buf[4096], *str; json *js; ut *cfg; /* read file contents, ignoring empty lines and comments */ fp = fopen(mg->options.conf_file, "r"); if (!fp) { dbg(0, "%s: fopen() failed: %s\n", mg->options.conf_file, strerror(errno)); return 3; } xs = xstr_create("{", mg->mmtmp); while (fgets(buf, sizeof buf, fp)) { str = pjf_trim(buf); if (!str || !str[0] || str[0] == '#') continue; xstr_append(xs, str); } xstr_append_char(xs, '}'); fclose(fp); /* parse config file as loose JSON */ js = json_create(mg->mmtmp); json_setopt(js, JSON_LOOSE, 1); cfg = json_parse(js, xstr_string(xs)); if (!ut_ok(cfg)) { dbg(0, "parsing config file failed: %s\n", ut_err(cfg)); return 1; } /* parse config */ return (parse_config_ut(mg, cfg) ? 2 : 0); }
static bool readjson_len(struct req *req, int len) { char buf[BUFSIZ]; xstr *xs = xstr_create("", req); json *js; if (len < 0) { while (fgets(buf, sizeof(buf), stdin)) { if (!buf[0] || buf[0] == '\n') break; xstr_append(xs, buf); } } else { int r; while ((r = fread(buf, 1, MIN(len, sizeof(buf)), stdin))) { if (r < 0) { dbg(5, "fread() returned %d, len=%d\n", r, len); break; } /* always appends \0 */ xstr_append_size(xs, buf, r); len -= r; if (len <= 0) break; } } /* eof? */ if (xstr_length(xs) == 0) exit(0); js = json_create(req); req->params = json_parse(js, xstr_string(xs)); return common(req, false); }
/* this probably needs a wise rewrite */ static char *fill_query(struct req *req, char *orig_query, tlist *data) { int i, qs; enum fq_state { NORMAL, INQ } state = NORMAL; xstr *query; MYSQL *conn; ut *arg, *el, *el2; tlist *list, *list2; bool atleastone, atleastone2; #define iskeyw(a) (sizeof(a) == i - qs && strncmp((a), orig_query + qs + 1, sizeof(a) - 1) == 0) /* XXX: uses list and el */ #define appendlist(utlist) do { \ atleastone = false; \ xstr_append(query, "("); \ list = ut_tlist(utlist); \ TLIST_ITER_LOOP(list, el) { \ if (atleastone) \ xstr_append_char(query, ','); \ xstr_append(query, \ pb("\"%s\"", escape(conn, ut_xstr(el)))); \ atleastone = true; \ } \ xstr_append(query, ")"); \ } while(0); conn = uthp_ptr(req->prv, "sqler", "conn"); query = xstr_create("", req); tlist_reset(data); for (i = 0; orig_query[i]; i++) { switch (state) { case NORMAL: if (orig_query[i] == '?') { qs = i; state = INQ; } else { xstr_append_char(query, orig_query[i]); } break; case INQ: if (orig_query[i] == '?') { if (iskeyw("login")) { xstr_append(query, pb("\"%s\"", uthp_char(req->prv, "sqler", "login"))); } else if (iskeyw("role")) { xstr_append(query, pb("\"%s\"", uthp_char(req->prv, "sqler", "role"))); } else { /* probably needs an arg */ arg = tlist_iter(data); if (arg) { if (iskeyw("int")) { xstr_append(query, pb("%d", ut_int(arg))); } else if (iskeyw("str")) { xstr_append(query, pb("\"%s\"", escape(conn, ut_xstr(arg)))); } else if (iskeyw("dbl")) { xstr_append(query, pb("%g", ut_double(arg))); } else if (iskeyw("login")) { xstr_append(query, pb("\"%s\"", uthp_char(req->prv, "sqler", "login"))); } else if (iskeyw("role")) { xstr_append(query, pb("\"%s\"", uthp_char(req->prv, "sqler", "role"))); } else if (iskeyw("array")) { appendlist(arg); } else if (iskeyw("arrays")) { atleastone2 = false; list2 = ut_tlist(arg); TLIST_ITER_LOOP(list2, el2) { if (atleastone2) xstr_append_char(query, ','); appendlist(el2); atleastone2 = true; } } /* XXX: arg eaten by unrecognizible substitution */ } } state = NORMAL; } else if (orig_query[i] < 'a' || orig_query[i] > 'z') { rollback: while (qs <= i) xstr_append_char(query, orig_query[qs++]); state = NORMAL; } break; }
bool readhttp(struct req *req) { enum http_type ht; char first[256], buf[BUFSIZ], *ct, *cl, *ac, *uri, *auth; int len; xstr *xs = xstr_create("", req); /* read query */ if (!fgets(first, sizeof(first), stdin) || first[0] == '\n') exit(0); /* eof */ if (strncmp(first, "POST ", 5) == 0) { ht = POST; uri = first + 5; } else if (strncmp(first, "OPTIONS ", 8) == 0) { ht = OPTIONS; uri = first + 8; } else if (strncmp(first, "GET ", 4) == 0 && O.http.htdocs) { /* @1 */ ht = GET; uri = first + 4; } else { dbg(4, "invalid method: %s\n", first); return errmsg("Invalid HTTP method"); } /* read headers */ while (fgets(buf, sizeof(buf), stdin)) { if (!buf[0] || buf[0] == '\n' || buf[0] == '\r') break; xstr_append(xs, buf); } req->http.headers = rfc822_parse(xstr_string(xs), req); /* fetch authentication information ASAP */ auth = thash_get(req->http.headers, "Authorization"); if (auth && strncmp(auth, "Basic ", 6) == 0) { xstr *ad = asn_b64_dec(auth+6, req); char *pass = strchr(xstr_string(ad), ':'); if (pass) { *pass++ = '\0'; req->http.user = xstr_string(ad); req->http.pass = pass; } } const char *cc = thash_get(req->http.headers, "Connection"); if (cc && (streq(cc, "close") || streq(cc, "Close"))) req->last = true; if (ht == OPTIONS) return errcode(JSON_RPC_HTTP_OPTIONS); /* handle static query, note that htdocs!=NULL checked @1 */ if (ht == GET) { req->http.needauth = true; char *space = strchr(uri, ' '); if (space) *space = '\0'; char *params = strchr(uri, '?'); if (params) *params = '\0'; if (streq(uri, "/")) { uri = "/index.html"; } else if (strstr(uri, "..")) { dbg(4, "invalid uri: '%s'\n", uri); return errcode(JSON_RPC_HTTP_NOT_FOUND); } req->http.uripath = mmatic_printf(req, "%s%s", O.http.htdocs, uri); if (asn_isfile(req->http.uripath) > 0) { dbg(4, "GET '%s'\n", req->http.uripath); return errcode(JSON_RPC_HTTP_GET); } dbg(4, "not found: '%s'\n", uri); req->http.uripath = NULL; return errcode(JSON_RPC_HTTP_NOT_FOUND); } /* = POST - ie. normal RPC call = */ ct = thash_get(req->http.headers, "Content-Type"); if (!ct) return errmsg("Content-Type needed"); if (strncmp(ct, "application/json", 16) != 0) return errmsg("Unsupported Content-Type"); ac = thash_get(req->http.headers, "Accept"); if (!ac) return errmsg("Accept needed"); if (!strstr(ac, "application/json") && !strstr(ac, "*/*")) return errmsg("Unsupported Accept"); /* read the query */ cl = thash_get(req->http.headers, "Content-Length"); if (!cl) return errmsg("Content-Length needed"); len = atoi(cl); if (len < 0) return errmsg("Unsupported Content-Length"); return readjson_len(req, len); }