static int rest_stream_data(noit_http_rest_closure_t *restc, int npats, char **pats) { /* We're here and want to subvert the rest system */ const char *document_domain = NULL; noit_http_session_ctx *ctx = restc->http_ctx; noit_http_connection *conn = noit_http_session_connection(ctx); eventer_t e; acceptor_closure_t *ac = restc->ac; /* Rewire the handler */ if(ac->service_ctx_free) ac->service_ctx_free(ac->service_ctx); ac->service_ctx = ctx; ac->service_ctx_free = noit_http_ctx_acceptor_free; if(!noit_hash_retr_str(ac->config, "document_domain", strlen("document_domain"), &document_domain)) { noitL(noit_error, "Document domain not set! Realtime streaming will be broken\n"); document_domain = ""; } noit_http_process_querystring(noit_http_session_request(ctx)); /* Rewire the http context */ e = noit_http_connection_event(conn); e->callback = stratcon_realtime_http_handler; noit_http_session_set_dispatcher(ctx, stratcon_request_dispatcher, alloc_realtime_context(document_domain)); return stratcon_request_dispatcher(ctx); }
noit_boolean noit_http_rest_client_cert_auth(noit_http_rest_closure_t *restc, int npats, char **pats) { struct noit_rest_acl *acl; struct noit_rest_acl_rule *rule; noit_http_request *req = noit_http_session_request(restc->http_ctx); const char *uri_str; const char *remote_cn = ""; int ovector[30]; if(restc->remote_cn) remote_cn = restc->remote_cn; uri_str = noit_http_request_uri_str(req); for(acl = global_rest_acls; acl; acl = acl->next) { if(acl->cn && pcre_exec(acl->cn, NULL, remote_cn, 0, 0, 0, ovector, sizeof(ovector)/sizeof(*ovector)) <= 0) continue; if(acl->url && pcre_exec(acl->url, NULL, uri_str, strlen(uri_str), 0, 0, ovector, sizeof(ovector)/sizeof(*ovector)) <= 0) continue; for(rule = acl->rules; rule; rule = rule->next) { if(rule->cn && pcre_exec(rule->cn, NULL, remote_cn, 0, 0, 0, ovector, sizeof(ovector)/sizeof(*ovector)) <= 0) continue; if(rule->url && pcre_exec(rule->url, NULL, uri_str, strlen(uri_str), 0, 0, ovector, sizeof(ovector)/sizeof(*ovector)) <= 0) continue; return rule->allow; } return acl->allow; } return noit_false; }
static rest_request_handler noit_http_get_handler(noit_http_rest_closure_t *restc) { struct rule_container *cont = NULL; struct rest_url_dispatcher *rule; noit_http_request *req = noit_http_session_request(restc->http_ctx); const char *uri_str; const char *eoq, *eob; uri_str = noit_http_request_uri_str(req); eoq = strchr(uri_str, '?'); if(!eoq) eoq = uri_str + strlen(uri_str); eob = eoq - 1; /* find the right base */ while(1) { void *vcont; while(eob >= uri_str && *eob != '/') eob--; if(eob < uri_str) break; /* off the front */ if(noit_hash_retrieve(&dispatch_points, uri_str, eob - uri_str + 1, &vcont)) { cont = vcont; eob++; /* move past the determined base */ break; } eob--; } if(!cont) return NULL; for(rule = cont->rules; rule; rule = rule->next) { int ovector[30]; int cnt; if(strcmp(rule->method, noit_http_request_method_str(req))) continue; if((cnt = pcre_exec(rule->expression, rule->extra, eob, eoq - eob, 0, 0, ovector, sizeof(ovector)/sizeof(*ovector))) > 0) { /* We match, set 'er up */ restc->fastpath = rule->handler; restc->nparams = cnt - 1; if(restc->nparams) { restc->params = calloc(restc->nparams, sizeof(*restc->params)); for(cnt = 0; cnt < restc->nparams; cnt++) { int start = ovector[(cnt+1)*2]; int end = ovector[(cnt+1)*2+1]; restc->params[cnt] = malloc(end - start + 1); memcpy(restc->params[cnt], eob + start, end - start); restc->params[cnt][end - start] = '\0'; } } if(rule->auth && !rule->auth(restc, restc->nparams, restc->params)) return noit_http_rest_permission_denied; return restc->fastpath; } } return NULL; }
int noit_rest_eventer_logs(noit_http_rest_closure_t *restc, int n, char **p) { char *endptr = NULL; const char *since_s, *last_s; const char *jsonstr; char errbuf[128]; unsigned long long since; int last = 0; struct json_object *doc; noit_log_stream_t ls; noit_http_request *req = noit_http_session_request(restc->http_ctx); since_s = noit_http_request_querystring(req, "since"); if(since_s) since = strtoull(since_s, &endptr, 10); last_s = noit_http_request_querystring(req, "last"); if(last_s) last = atoi(last_s); assert(n==1); ls = noit_log_stream_find(p[0]); if(!ls || strcmp(noit_log_stream_get_type(ls),"memory")) goto not_found; doc = json_object_new_array(); if(endptr != since_s) noit_log_memory_lines_since(ls, since, json_spit_log, doc); else noit_log_memory_lines(ls, last, json_spit_log, doc); noit_http_response_ok(restc->http_ctx, "application/json"); jsonstr = json_object_to_json_string(doc); noit_http_response_append(restc->http_ctx, jsonstr, strlen(jsonstr)); noit_http_response_append(restc->http_ctx, "\n", 1); json_object_put(doc); noit_http_response_end(restc->http_ctx); return 0; not_found: doc = json_object_new_object(); snprintf(errbuf, sizeof(errbuf), "log '%s' not found", p[0]); json_object_object_add(doc, "error", json_object_new_string(errbuf)); jsonstr = json_object_to_json_string(doc); noit_http_response_not_found(restc->http_ctx, "application/json"); noit_http_response_append(restc->http_ctx, jsonstr, strlen(jsonstr)); noit_http_response_append(restc->http_ctx, "\n", 1); json_object_put(doc); noit_http_response_end(restc->http_ctx); return 0; }
void * rest_get_raw_upload(noit_http_rest_closure_t *restc, int *mask, int *complete, int *size) { struct rest_raw_payload *rxc; noit_http_request *req = noit_http_session_request(restc->http_ctx); *size = 0; if(restc->call_closure == NULL) { restc->call_closure = calloc(1, sizeof(*rxc)); restc->call_closure_free = rest_raw_payload_free; } rxc = restc->call_closure; while(!rxc->complete) { int len; if(rxc->len == rxc->allocd) { char *b; rxc->allocd += 32768; b = rxc->buffer ? realloc(rxc->buffer, rxc->allocd) : malloc(rxc->allocd); if(!b) { *complete = 1; return NULL; } rxc->buffer = b; } len = noit_http_session_req_consume(restc->http_ctx, rxc->buffer + rxc->len, rxc->allocd - rxc->len, rxc->allocd - rxc->len, mask); if(len > 0) rxc->len += len; if(len < 0 && errno == EAGAIN) return NULL; else if(len < 0) { *complete = 1; return NULL; } if(rxc->len == noit_http_request_content_length(req)) { *size = rxc->len; rxc->complete = 1; } } *complete = 1; return rxc->buffer; }
int stratcon_request_dispatcher(noit_http_session_ctx *ctx) { const char *key, *value; realtime_context *rc = noit_http_session_dispatcher_closure(ctx); int klen; noit_hash_iter iter = NOIT_HASH_ITER_ZERO; noit_http_request *req = noit_http_session_request(ctx); if(rc->setup == RC_INITIAL) { eventer_t completion; struct realtime_tracker *node; char c[1024]; int num_interests; const char *uri_str = noit_http_request_uri_str(req); noit_hash_table *headers = noit_http_request_headers_table(req); num_interests = stratcon_realtime_uri_parse(rc, uri_str); if(num_interests == 0) { noit_http_response_status_set(ctx, 404, "OK"); noit_http_response_option_set(ctx, NOIT_HTTP_CLOSE); noit_http_response_end(ctx); return 0; } noitL(noit_error, "http: %s %s %s\n", noit_http_request_method_str(req), uri_str, noit_http_request_protocol_str(req)); while(noit_hash_next_str(headers, &iter, &key, &klen, &value)) { noitL(noit_error, "http: [%s: %s]\n", key, value); } noit_http_response_status_set(ctx, 200, "OK"); noit_http_response_option_set(ctx, NOIT_HTTP_CHUNKED); /*noit_http_response_option_set(ctx, NOIT_HTTP_GZIP);*/ /*noit_http_response_option_set(ctx, NOIT_HTTP_DEFLATE);*/ noit_http_response_header_set(ctx, "Content-Type", "text/html"); snprintf(c, sizeof(c), "<html><head><script>document.domain='%s';</script></head><body>\n", rc->document_domain); noit_http_response_append(ctx, c, strlen(c)); /* this dumb crap is to make some browsers happy (Safari) */ memset(c, ' ', sizeof(c)); noit_http_response_append(ctx, c, sizeof(c)); noit_http_response_flush(ctx, noit_false); rc->setup = RC_REQ_RECV; /* Each interest references the ctx */ for(node = rc->checklist; node; node = node->next) { char uuid_str[UUID_STR_LEN+1]; noit_http_session_ref_inc(ctx); uuid_unparse_lower(node->checkid, uuid_str); noitL(noit_error, "Resolving uuid: %s\n", uuid_str); } completion = eventer_alloc(); completion->mask = EVENTER_TIMER; completion->callback = stratcon_realtime_http_postresolve; completion->closure = ctx; gettimeofday(&completion->whence, NULL); stratcon_datastore_push(DS_OP_FIND_COMPLETE, NULL, NULL, rc->checklist, completion); } return EVENTER_EXCEPTION; }
int stratcon_line_to_javascript(noit_http_session_ctx *ctx, char *in_buff, u_int32_t *inc_id) { char buffer[1024]; char *scp, *ecp, *token, *buff; int i, len, cnt; const char *v, *cb = NULL; noit_hash_table json = NOIT_HASH_EMPTY; noit_http_request *req = noit_http_session_request(ctx); char s_inc_id[42]; char **outrows = NULL; cb = noit_http_request_querystring(req, "cb"); for(v = cb; v && *v; v++) if(!((*v >= '0' && *v <= '9') || (*v >= 'a' && *v <= 'z') || (*v >= 'A' && *v <= 'Z') || (*v == '_') || (*v == '.'))) { cb = NULL; break; } if(!cb) cb = "window.parent.plot_iframe_data"; #define BAIL_HTTP_WRITE do { \ if(outrows) { \ for(i=0;i<cnt;i++) if(outrows[i]) free(outrows[i]); \ free(outrows); \ } \ noit_hash_destroy(&json, NULL, free); \ noitL(noit_error, "javascript emit failed: %s:%s:%d\n", \ __FILE__, __FUNCTION__, __LINE__); \ return -1; \ } while(0) #define PROCESS_NEXT_FIELD(t,l) do { \ if(!*scp) goto bad_row; \ ecp = strchr(scp, '\t'); \ if(!ecp) goto bad_row; \ t = scp; \ l = (ecp-scp); \ scp = ecp + 1; \ } while(0) #define PROCESS_LAST_FIELD(t,l) do { \ if(!*scp) ecp = scp; \ else { \ ecp = scp + strlen(scp); /* Puts us at the '\0' */ \ if(*(ecp-1) == '\n') ecp--; /* We back up on letter if we ended in \n */ \ } \ t = scp; \ l = (ecp-scp); \ } while(0) noitL(noit_error, "recv(%s)\n", in_buff); if(in_buff[0] == 'B' && in_buff[1] != '\0' && in_buff[2] == '\t') { cnt = noit_check_log_b_to_sm(in_buff, strlen(in_buff), &outrows); } else { cnt = 1; outrows = malloc(sizeof(*outrows)); outrows[0] = strdup(in_buff); } for(i=0; i<cnt; i++) { buff = outrows[i]; if(!buff) continue; noitL(noit_error, "recv_xlt(%s)\n", buff); scp = buff; PROCESS_NEXT_FIELD(token,len); /* Skip the leader */ if(buff[1] == '\t' && (buff[0] == 'M' || buff[0] == 'S')) { char target[256], module[256], name[256], uuid_str[UUID_STR_LEN+1]; noit_http_request *req = noit_http_session_request(ctx); noit_hash_table *qs; noit_hash_iter iter = NOIT_HASH_ITER_ZERO; const char *key; int klen, i=0; void *vval; char type[2] = { '\0', '\0' }; type[0] = buff[0]; #define ra_write(a,b) if(noit_http_response_append(ctx, a, b) == noit_false) BAIL_HTTP_WRITE snprintf(s_inc_id, sizeof(s_inc_id), "script-%08x", (*inc_id)++); snprintf(buffer, sizeof(buffer), "<script id=\"%s\">%s({", s_inc_id, cb); ra_write(buffer, strlen(buffer)); qs = noit_http_request_querystring_table(req); while(noit_hash_next(qs, &iter, &key, &klen, &vval)) { if(!strcmp(key, "cb")) continue; noit_hash_store(&json, key, klen, strdup(vval ?(char *)vval : "true")); } /* Time */ noit_hash_store(&json, "script_id", 9, strdup(s_inc_id)); noit_hash_store(&json, "type", 4, strdup(type)); PROCESS_NEXT_FIELD(token,len); noit_hash_store(&json, "time", 4, noit__strndup(token, len)); /* UUID */ PROCESS_NEXT_FIELD(token,len); noit_check_extended_id_split(token, len, target, sizeof(target), module, sizeof(module), name, sizeof(name), uuid_str, sizeof(uuid_str)); if(*uuid_str) noit_hash_store(&json, "id", 2, noit__strndup(uuid_str, strlen(uuid_str))); if(*target) noit_hash_store(&json, "check_target", 12, noit__strndup(target, strlen(target))); if(*module) noit_hash_store(&json, "check_module", 12, noit__strndup(module, strlen(module))); if(*name) noit_hash_store(&json, "check_name", 10, noit__strndup(name, strlen(name))); if(buff[0] == 'M') { /* name */ PROCESS_NEXT_FIELD(token,len); noit_hash_store(&json, "metric_name", 11, noit__strndup(token, len)); /* type */ PROCESS_NEXT_FIELD(token,len); noit_hash_store(&json, "metric_type", 11, noit__strndup(token, len)); /* value */ PROCESS_LAST_FIELD(token,len); /* value */ noit_hash_store(&json, "value", 5, noit__strndup(token, len)); } else if(buff[0] == 'S') { /* state */ PROCESS_NEXT_FIELD(token,len); noit_hash_store(&json, "check_state", 11, noit__strndup(token, len)); /* availability */ PROCESS_NEXT_FIELD(token,len); noit_hash_store(&json, "check_availability", 18, noit__strndup(token, len)); /* duration */ PROCESS_NEXT_FIELD(token,len); noit_hash_store(&json, "check_duration_ms", 17, noit__strndup(token, len)); /* status */ PROCESS_LAST_FIELD(token,len); noit_hash_store(&json, "status_message", 14, noit__strndup(token, len)); } memset(&iter, 0, sizeof(iter)); while(noit_hash_next(&json, &iter, &key, &klen, &vval)) { char *val = (char *)vval; if(i++) ra_write(",", 1); ra_write("\"", 1); ra_write(key, klen); ra_write("\":\"", 3); while(*val) { if(*val == '\"' || *val == '\\') { ra_write((char *)"\\", 1); } if(isprint(*val)) { ra_write((char *)val, 1); } else { char od[5]; snprintf(od, sizeof(od), "\\%03o", *((unsigned char *)val)); ra_write(od, strlen(od)); } val++; } ra_write("\"", 1); } snprintf(buffer, sizeof(buffer), "});</script>\n"); ra_write(buffer, strlen(buffer)); if(noit_http_response_flush(ctx, noit_false) == noit_false) BAIL_HTTP_WRITE; } noit_hash_destroy(&json, NULL, free); memset(&json, 0, sizeof(json)); } if(outrows) { for(i=0;i<cnt;i++) if(outrows[i]) free(outrows[i]); free(outrows); } return 0; bad_row: BAIL_HTTP_WRITE; }
static int noit_http_ctx_index_func(lua_State *L) { OO_LUA_DECL(L, noit_http_session_ctx, http_ctx, k); switch(*k) { case 'C': if(!strcmp(k, "CHUNKED")) { lua_pushinteger(L, NOIT_HTTP_CHUNKED); return 1; } if(!strcmp(k, "CLOSE")) { lua_pushinteger(L, NOIT_HTTP_CLOSE); return 1; } break; case 'D': if(!strcmp(k, "DEFATE")) { lua_pushinteger(L, NOIT_HTTP_DEFLATE); return 1; } break; case 'G': if(!strcmp(k, "GZIP")) { lua_pushinteger(L, NOIT_HTTP_GZIP); return 1; } break; case 'f': if(!strcmp(k, "flush")) { lua_pushlightuserdata(L, http_ctx); lua_pushcclosure(L, noit_lua_http_flush, 1); return 1; } if(!strcmp(k, "flush_end")) { lua_pushlightuserdata(L, http_ctx); lua_pushcclosure(L, noit_lua_http_flush_and_end, 1); return 1; } break; case 'h': if(!strcmp(k, "htmlentities")) { lua_getglobal(L, "noit"); lua_getfield(L, -1, "utf8tohtml"); lua_remove(L, -2); /* pop noit */ return 1; } if(!strcmp(k, "header")) { lua_pushlightuserdata(L, http_ctx); lua_pushcclosure(L, noit_lua_http_header_set, 1); return 1; } break; case 'o': if(!strcmp(k, "option")) { lua_pushlightuserdata(L, http_ctx); lua_pushcclosure(L, noit_lua_http_option_set, 1); return 1; } break; case 'r': if(!strcmp(k, "request")) { lua_pushlightuserdata(L, noit_http_session_request(http_ctx)); lua_pushcclosure(L, noit_lua_http_request_func, 1); return 1; } if(!strcmp(k, "response")) { return 0; } break; case 's': if(!strcmp(k, "status")) { lua_pushlightuserdata(L, http_ctx); lua_pushcclosure(L, noit_lua_http_status_set, 1); return 1; } if(!strcmp(k, "set_cookie")) { lua_pushlightuserdata(L, http_ctx); lua_pushcclosure(L, noit_lua_http_set_cookie, 1); return 1; } break; case 'u': if(!strcmp(k, "url_decode")) { lua_pushcclosure(L, noit_lua_http_url_decode, 0); return 1; } if(!strcmp(k, "url_encode")) { lua_pushcclosure(L, noit_lua_http_url_encode, 0); return 1; } break; case 'w': if(!strcmp(k, "write")) { lua_pushlightuserdata(L, http_ctx); lua_pushcclosure(L, noit_lua_http_write, 1); return 1; } if(!strcmp(k, "write_fd")) { lua_pushlightuserdata(L, http_ctx); lua_pushcclosure(L, noit_lua_http_write_fd, 1); return 1; } break; default: break; } luaL_error(L, "noit_http_session_ctx no such element: %s", k); return 0; }