void webpopup_result_free(webpopup_result_t *wr) { free(wr->wr_trapped.url); free(wr->wr_trapped.hostname); free(wr->wr_trapped.path); http_headers_free(&wr->wr_trapped.qargs); free(wr); }
static htsmsg_t * tmdb_load_movie_cast(const char *lookup_id) { char url[300]; char errbuf[256]; buf_t *result; snprintf(url, sizeof(url), "http://api.themoviedb.org/3/movie/%s/casts", lookup_id); retry: tmdb_check_rate_limit(); int http_response_code = 0; struct http_header_list response_headers; LIST_INIT(&response_headers); result = fa_load(url, FA_LOAD_ERRBUF(errbuf, sizeof(errbuf)), FA_LOAD_QUERY_ARG("api_key", TMDB_APIKEY), FA_LOAD_QUERY_ARG("language", getlang()), FA_LOAD_RESPONSE_HEADERS(&response_headers), FA_LOAD_PROTOCOL_CODE(&http_response_code), FA_LOAD_FLAGS(FA_COMPRESSION), NULL); if(result == NULL) { if(http_response_code == 429) { tmdb_handle_rate_limit(&response_headers); goto retry; } http_headers_free(&response_headers); TRACE(TRACE_INFO, "TMDB", "Load error %s", errbuf); return NULL; } http_headers_free(&response_headers); htsmsg_t *doc = htsmsg_json_deserialize2(buf_cstr(result), errbuf, sizeof(errbuf)); if(doc == NULL) { TRACE(TRACE_ERROR, "TMDB", "Got bad JSON from %s -- %s", url, errbuf); } buf_release(result); return doc; }
void do_died(subuser *sub) { if (sub->state == ALIVE) { sub->state = ADIED; sub->headers.sent = 0; http_headers_free(sub->headers.content); sub->headers.content = NULL; shutdown(sub->client->fd, 2); } }
static void tmdb_handle_rate_limit(struct http_header_list *response_headers) { const char *retry = http_header_get(response_headers, "retry-after"); int waittime = 5; if(retry != NULL) waittime = atoi(retry) + 1; http_headers_free(response_headers); TMDB_TRACE("Rate limited - Throttling requests for %d seconds", waittime); hts_mutex_lock(&tmdb_mutex); tmdb_no_request_before = arch_get_ts() + waittime * 1000000; hts_mutex_unlock(&tmdb_mutex); }
int soap_exec(const char *uri, const char *service, int version, const char *method, htsmsg_t *in, htsmsg_t **outp, char *errbuf, size_t errlen) { int r; htsmsg_t *out; htsbuf_queue_t post; buf_t *result; struct http_header_list hdrs = {0}; char tmp[100]; htsbuf_queue_init(&post, 0); htsbuf_qprintf(&post, "<?xml version=\"1.0\" encoding=\"utf-8\"?>" "<s:Envelope s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" "<s:Body><ns0:%s xmlns:ns0=\"urn:schemas-upnp-org:service:%s:%d\">", method, service, version); soap_encode_args(&post, in); htsbuf_qprintf(&post, "</ns0:%s></s:Body></s:Envelope>", method); snprintf(tmp, sizeof(tmp),"\"urn:schemas-upnp-org:service:%s:%d#%s\"", service, version, method); http_header_add(&hdrs, "SOAPACTION", tmp, 0); r = http_request(uri, NULL, &result, errbuf, errlen, &post, "text/xml; charset=\"utf-8\"", 0, NULL, &hdrs, NULL, NULL, NULL); http_headers_free(&hdrs); htsbuf_queue_flush(&post); if(r) return -1; out = htsmsg_xml_deserialize_buf2(result, errbuf, errlen); if(out == NULL) return -1; snprintf(tmp, sizeof(tmp), "urn:schemas-upnp-org:service:%s:%d%sResponse", service, version, method); htsmsg_t *outargs = htsmsg_get_map_multi(out, "tags", "http://schemas.xmlsoap.org/soap/envelope/Envelope", "tags", "http://schemas.xmlsoap.org/soap/envelope/Body", "tags", tmp, "tags", NULL); if(outargs != NULL) { htsmsg_field_t *f; htsmsg_t *out = htsmsg_create_map(); // Convert args from XML style to more compact style HTSMSG_FOREACH(f, outargs) { htsmsg_t *a; const char *s; if((a = htsmsg_get_map_by_field(f)) == NULL) continue; if((s = htsmsg_get_str(a, "cdata")) != NULL) htsmsg_add_str(out, f->hmf_name, s); }
int process_cmd(json_item *ijson, struct _cmd_process *pc, subuser **iuser, acetables *g_ape) { callback *cmdback, tmpback = {handle_bad_cmd, NEED_NOTHING}; json_item *rjson = json_lookup(ijson->jchild.child, "cmd"), *jchl; subuser *sub = pc->sub; unsigned int flag; unsigned short int attach = 1; if (rjson != NULL && rjson->jval.vu.str.value != NULL) { callbackp cp; cp.client = NULL; cp.cmd = rjson->jval.vu.str.value; cp.data = NULL; cp.hlines = NULL; json_item *jsid; if ((cmdback = (callback *)hashtbl_seek(g_ape->hCallback, rjson->jval.vu.str.value)) == NULL) { cmdback = &tmpback; } if ((pc->guser == NULL && (jsid = json_lookup(ijson->jchild.child, "sessid")) != NULL && jsid->jval.vu.str.value != NULL)) { pc->guser = seek_user_id(jsid->jval.vu.str.value, g_ape); } if (cmdback->need != NEED_NOTHING || pc->guser != NULL) { // We process the connection like a "NEED_SESSID" if the user provide its key if (pc->guser == NULL) { RAW *newraw; json_item *jlist = json_new_object(); json_set_property_strZ(jlist, "code", "004"); json_set_property_strZ(jlist, "value", "BAD_SESSID"); newraw = forge_raw(RAW_ERR, jlist); send_raw_inline(pc->client, pc->transport, newraw, g_ape); return (CONNECT_SHUTDOWN); } else if (sub == NULL) { sub = getsubuser(pc->guser, pc->host); if (sub != NULL && sub->client->fd != pc->client->fd && sub->state == ALIVE) { /* The user open a new connection while he already has one openned */ struct _transport_open_same_host_p retval = transport_open_same_host(sub, pc->client, pc->guser->transport); if (retval.client_close != NULL) { // Send CLOSE if no response has been sent yet if (!sub->headers.sent) { RAW *newraw; json_item *jlist = json_new_object(); json_set_property_strZ(jlist, "value", "null"); newraw = forge_raw("CLOSE", jlist); send_raw_inline((retval.client_close->fd == pc->client->fd ? pc->client : sub->client), pc->transport, newraw, g_ape); } // It's not safe to leave the subuser pointer in co->attach anymore // since subuser could subsequently be deleted, leaving a pointer into free heap. // So, let this socket finish up on its own and pretend its already finished. sub->state = ADIED; sub->headers.sent = 0; http_headers_free(sub->headers.content); sub->headers.content = NULL; sub->burn_after_writing = 0; g_ape->co[retval.client_close->fd]->attach = NULL; safe_shutdown(retval.client_close->fd, g_ape); } sub->client = cp.client = retval.client_listener; sub->state = retval.substate; attach = retval.attach; } else if (sub == NULL) { sub = addsubuser(pc->client, pc->host, pc->guser, g_ape); if (sub != NULL) { subuser_restor(sub, g_ape); } } else if (sub != NULL) { sub->client = pc->client; } pc->guser->idle = (long int)time(NULL); // update user idle sub->idle = pc->guser->idle; // Update subuser idle } } if (pc->guser != NULL && sub != NULL && (jchl = json_lookup(ijson->jchild.child, "chl")) != NULL /*&& jchl->jval.vu.integer_value > sub->current_chl*/) { sub->current_chl = jchl->jval.vu.integer_value; } #if 0 else if (pc->guser != NULL && sub != NULL) { /* if a bad challenge is detected, we are stoping walking on cmds */ send_error(pc->guser, "BAD_CHL", "250", g_ape); sub->state = ALIVE; return (CONNECT_KEEPALIVE); } #endif cp.param = json_lookup(ijson->jchild.child, "params"); cp.client = (cp.client != NULL ? cp.client : pc->client); cp.call_user = pc->guser; cp.call_subuser = sub; cp.g_ape = g_ape; cp.host = pc->host; cp.ip = pc->ip; cp.chl = (sub != NULL ? sub->current_chl : 0); cp.transport = pc->transport; cp.hlines = pc->hlines; /* Little hack to access user object on connect hook callback (preallocate an user) */ if (strncasecmp(cp.cmd, "CONNECT", 7) == 0 && cp.cmd[7] == '\0') { pc->guser = cp.call_user = adduser(cp.client, cp.host, cp.ip, NULL, g_ape); pc->guser->transport = pc->transport; sub = cp.call_subuser = cp.call_user->subuser; } if ((flag = call_cmd_hook(cp.cmd, &cp, g_ape)) == RETURN_CONTINUE) { flag = cmdback->func(&cp); } if (flag & RETURN_NULL) { pc->guser = NULL; } else if (flag & RETURN_BAD_PARAMS) { RAW *newraw; json_item *jlist = json_new_object(); if (cp.chl) { json_set_property_intN(jlist, "chl", 3, cp.chl); } json_set_property_strZ(jlist, "code", "001"); json_set_property_strZ(jlist, "value", "BAD_PARAMS"); newraw = forge_raw(RAW_ERR, jlist); if (cp.call_user != NULL) { //cp.call_user->istmp = 0; if (sub == NULL) { sub = getsubuser(pc->guser, pc->host); } post_raw_sub(newraw, sub, g_ape); } else { send_raw_inline(pc->client, pc->transport, newraw, g_ape); } //guser = NULL; } else if (flag & RETURN_BAD_CMD) { RAW *newraw; json_item *jlist = json_new_object(); if (cp.chl) { json_set_property_intN(jlist, "chl", 3, cp.chl); } json_set_property_strZ(jlist, "code", "003"); json_set_property_strZ(jlist, "value", "BAD_CMD"); newraw = forge_raw(RAW_ERR, jlist); if (cp.call_user != NULL) { if (sub == NULL) { sub = getsubuser(pc->guser, pc->host); } post_raw_sub(newraw, sub, g_ape); } else { send_raw_inline(pc->client, pc->transport, newraw, g_ape); } } if (pc->guser != NULL) { if (sub == NULL) { sub = getsubuser(pc->guser, pc->host); } if (iuser != NULL) { *iuser = (attach ? sub : NULL); } /* If tmpfd is set, we do not have any reasons to change its state */ sub->state = ALIVE; if (flag & RETURN_HANG || flag & RETURN_BAD_PARAMS) { return (CONNECT_KEEPALIVE); } } else if (flag & RETURN_HANG) { /* Doesn't need sessid */ return (CONNECT_KEEPALIVE); } else { return (CONNECT_SHUTDOWN); } } else { RAW *newraw; json_item *jlist = json_new_object(); json_set_property_strZ(jlist, "code", "003"); json_set_property_strZ(jlist, "value", "NO_CMD"); newraw = forge_raw(RAW_ERR, jlist); send_raw_inline(pc->client, pc->transport, newraw, g_ape); //printf("Cant find %s\n", rjson->jval.vu.str.value); return (CONNECT_SHUTDOWN); } return -1; }
void load_site_news(void) { #if ENABLE_WEBPOPUP struct http_header_list response_headers; buf_t *b; char errbuf[512]; b = fa_load("https://movian.tv/projects/movian/news.json", FA_LOAD_FLAGS(FA_DISABLE_AUTH | FA_COMPRESSION), FA_LOAD_RESPONSE_HEADERS(&response_headers), FA_LOAD_ERRBUF(errbuf, sizeof(errbuf)), NULL); if(b == NULL) { TRACE(TRACE_DEBUG, "News", "Unable to load news -- %s", errbuf); return; } const char *dateheader = http_header_get(&response_headers, "date"); if(dateheader == NULL) { buf_release(b); http_headers_free(&response_headers); return; } dateheader = mystrdupa(dateheader); http_headers_free(&response_headers); htsmsg_t *newsinfo = htsmsg_store_load("sitenews"); time_t no_news_before; if(newsinfo == NULL) newsinfo = htsmsg_create_map(); no_news_before = htsmsg_get_u32_or_default(newsinfo, "nothingbefore", 0); if(no_news_before == 0) { if(http_ctime(&no_news_before, dateheader)) { buf_release(b); htsmsg_release(newsinfo); return; } htsmsg_add_u32(newsinfo, "nothingbefore", no_news_before); htsmsg_store_save(newsinfo, "sitenews"); htsmsg_release(newsinfo); } htsmsg_t *doc = htsmsg_json_deserialize(buf_cstr(b)); buf_release(b); if(doc == NULL) { return; } hts_mutex_lock(&news_mutex); htsmsg_t *news = htsmsg_get_list(doc, "news"); if(news != NULL) { htsmsg_field_t *f; HTSMSG_FOREACH(f, news) { htsmsg_t *entry; if((entry = htsmsg_get_map_by_field(f)) == NULL) continue; const char *title = htsmsg_get_str(entry, "title"); const char *created_on = htsmsg_get_str(entry, "created_on"); int id = htsmsg_get_u32_or_default(entry, "id", 0); if(created_on == NULL || title == NULL || id == 0) continue; time_t t; if(parse_created_on_time(&t, created_on)) continue; if(t < no_news_before) continue; char idstr[64]; snprintf(idstr, sizeof(idstr), "sitenews:%d", id); prop_t *p = add_news_locked(idstr, title, NULL, "Read more", idstr); if(p != NULL) { prop_subscribe(PROP_SUB_TRACK_DESTROY, PROP_TAG_CALLBACK, open_news, p, PROP_TAG_ROOT, prop_create(p, "eventSink"), PROP_TAG_MUTEX, &news_mutex, NULL); } }
/** * mc is set if packet arrived on our multicast listening socket */ static void ssdp_input(int fd, int mc) { char buf[2000]; int r, cmd, self; struct http_header_list args; uint32_t myaddr; const char *usn; struct sockaddr_in si; #if defined(IP_RECVDSTADDR) struct msghdr msg; struct cmsghdr *cmsg; struct iovec iov; char ctrl[500]; iov.iov_base = buf; iov.iov_len = sizeof(buf); msg.msg_name = (struct sockaddr *)&si; msg.msg_namelen = sizeof(struct sockaddr_in); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = ctrl; msg.msg_controllen = sizeof(ctrl); r = recvmsg(fd, &msg, 0); if(r < 1) return; buf[r] = 0; myaddr = 0; for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg,cmsg)) { if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { struct in_addr *ia = (struct in_addr *)CMSG_DATA(cmsg); myaddr = ntohl(ia->s_addr); break; } } #else socklen_t slen = sizeof(struct sockaddr_in); netif_t *ni; r = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&si, &slen); if(r < 1) return; buf[r] = 0; ni = net_get_interfaces(); myaddr = ni ? ni[0].ipv4 : 0; free(ni); #endif if(!myaddr) return; LIST_INIT(&args); cmd = ssdp_parse(buf, &args); usn = http_header_get(&args, "usn"); self = usn != NULL && !strncmp(usn, "uuid:", 5) && !strncmp(usn + 5, ssdp_uuid, strlen(ssdp_uuid)); if(!self) { if(cmd == SSDP_NOTIFY && mc) ssdp_recv_notify(&args); if(cmd == SSDP_RESPONSE && !mc) ssdp_response(&args); if(cmd == SSDP_SEARCH && mc) ssdp_send_all(ssdp_fdu, myaddr, &si, NULL); } http_headers_free(&args); }