static void *fetch_rsrc_setup(struct fetch *parent_fetch, nsurl *url, bool only_2xx, bool downgrade_tls, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, const char **headers) { struct fetch_rsrc_context *ctx; ctx = (struct fetch_rsrc_context *)calloc(1, sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->parent_fetch = parent_fetch; /* TODO: keep as nsurl to avoid copy */ ctx->url = (char *)malloc(nsurl_length(url) + 1); if (ctx->url == NULL) { free(ctx); return NULL; } memcpy(ctx->url, nsurl_access(url), nsurl_length(url) + 1); RING_INSERT(ring, ctx); return ctx; }
/** * Dispatch a single job */ static bool fetch_dispatch_job(struct fetch *fetch) { RING_REMOVE(queue_ring, fetch); #ifdef DEBUG_FETCH_VERBOSE LOG(("Attempting to start fetch %p, fetcher %p, url %s", fetch, fetch->fetcher_handle, nsurl_access(fetch->url))); #endif if (!fetch->ops->start_fetch(fetch->fetcher_handle)) { RING_INSERT(queue_ring, fetch); /* Put it back on the end of the queue */ return false; } else { RING_INSERT(fetch_ring, fetch); fetch->fetch_is_active = true; return true; } }
void monkey_register_handler(const char *cmd, handle_command_fn fn) { monkey_cmdhandler_t *ret = calloc(sizeof(*ret), 1); if (ret == NULL) die("Unable to allocate handler"); ret->cmd = strdup(cmd); ret->fn = fn; RING_INSERT(handler_ring, ret); }
/* See hlcache.h for documentation */ nserror hlcache_handle_retrieve(nsurl *url, uint32_t flags, nsurl *referer, llcache_post_data *post, hlcache_handle_callback cb, void *pw, hlcache_child_context *child, content_type accepted_types, hlcache_handle **result) { hlcache_retrieval_ctx *ctx; nserror error; assert(cb != NULL); ctx = calloc(1, sizeof(hlcache_retrieval_ctx)); if (ctx == NULL) return NSERROR_NOMEM; ctx->handle = calloc(1, sizeof(hlcache_handle)); if (ctx->handle == NULL) { free(ctx); return NSERROR_NOMEM; } if (child != NULL) { if (child->charset != NULL) { ctx->child.charset = strdup(child->charset); if (ctx->child.charset == NULL) { free(ctx->handle); free(ctx); return NSERROR_NOMEM; } } ctx->child.quirks = child->quirks; } ctx->flags = flags; ctx->accepted_types = accepted_types; ctx->handle->cb = cb; ctx->handle->pw = pw; error = llcache_handle_retrieve(url, flags, referer, post, hlcache_llcache_callback, ctx, &ctx->llcache); if (error != NSERROR_OK) { free((char *) ctx->child.charset); free(ctx->handle); free(ctx); return error; } RING_INSERT(hlcache->retrieval_ctx_ring, ctx); *result = ctx->handle; return NSERROR_OK; }
nserror monkey_register_handler(const char *cmd, handle_command_fn fn) { monkey_cmdhandler_t *ret = calloc(sizeof(*ret), 1); if (ret == NULL) { LOG("Unable to allocate handler"); return NSERROR_NOMEM; } ret->cmd = strdup(cmd); ret->fn = fn; RING_INSERT(handler_ring, ret); return NSERROR_OK; }
void gui_401login_open(const char *url, const char *realm, nserror (*cb)(bool proceed, void *pw), void *cbpw) { monkey401_t *m4t = calloc(sizeof(*m4t), 1); if (m4t == NULL) cb(false, cbpw); m4t->cb = cb; m4t->pw = cbpw; m4t->num = m4_ctr++; RING_INSERT(m4_ring, m4t); fprintf(stdout, "401LOGIN OPEN M4 %u URL %s REALM %s\n", m4t->num, url, realm); }
/** * Cache a CURL handle for the provided host (if wanted) */ static void fetch_curl_cache_handle(CURL *handle, lwc_string *host) { #if LIBCURL_VERSION_NUM >= 0x071e00 /* 7.30.0 or later has its own connection caching; suppress ours */ curl_easy_cleanup(handle); return; #else struct cache_handle *h = 0; int c; RING_FINDBYLWCHOST(curl_handle_ring, h, host); if (h) { /* Already have a handle cached for this hostname */ curl_easy_cleanup(handle); return; } /* We do not have a handle cached, first up determine if the cache is full */ RING_GETSIZE(struct cache_handle, curl_handle_ring, c); if (c >= nsoption_int(max_cached_fetch_handles)) { /* Cache is full, so, we rotate the ring by one and * replace the oldest handle with this one. We do this * without freeing/allocating memory (except the * hostname) and without removing the entry from the * ring and then re-inserting it, in order to be as * efficient as we can. */ if (curl_handle_ring != NULL) { h = curl_handle_ring; curl_handle_ring = h->r_next; curl_easy_cleanup(h->handle); h->handle = handle; lwc_string_unref(h->host); h->host = lwc_string_ref(host); } else { /* Actually, we don't want to cache any handles */ curl_easy_cleanup(handle); } return; } /* The table isn't full yet, so make a shiny new handle to add to the ring */ h = (struct cache_handle*)malloc(sizeof(struct cache_handle)); h->handle = handle; h->host = lwc_string_ref(host); RING_INSERT(curl_handle_ring, h); #endif }
/** callback to set up a resource fetch context. */ static void * fetch_resource_setup(struct fetch *fetchh, nsurl *url, bool only_2xx, bool downgrade_tls, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, const char **headers) { struct fetch_resource_context *ctx; lwc_string *path; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->handler = fetch_resource_notfound_handler; if ((path = nsurl_get_component(url, NSURL_PATH)) != NULL) { uint32_t i; bool match; /* Ensure requested path is valid */ for (i = 0; i < fetch_resource_path_count; i++) { if (lwc_string_isequal(path, fetch_resource_map[i].path, &match) == lwc_error_ok && match) { ctx->redirect_url = nsurl_ref(fetch_resource_map[i].url); ctx->handler = fetch_resource_redirect_handler; break; } } lwc_string_unref(path); } ctx->url = nsurl_ref(url); ctx->fetchh = fetchh; RING_INSERT(ring, ctx); return ctx; }
nserror gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw) { monkey_cert_t *m4t = calloc(sizeof(*m4t), 1); if (m4t == NULL) { return NSERROR_NOMEM; } m4t->cb = cb; m4t->pw = cbpw; m4t->num = cert_ctr++; RING_INSERT(cert_ring, m4t); fprintf(stdout, "SSLCERT VERIFY CERT %u URL %s\n", m4t->num, nsurl_access(url)); return NSERROR_OK; }
/** callback to set up a about fetch context. */ static void * fetch_about_setup(struct fetch *fetchh, nsurl *url, bool only_2xx, bool downgrade_tls, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, const char **headers) { struct fetch_about_context *ctx; unsigned int handler_loop; lwc_string *path; bool match; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) return NULL; path = nsurl_get_component(url, NSURL_PATH); for (handler_loop = 0; handler_loop < about_handler_list_len; handler_loop++) { ctx->handler = about_handler_list[handler_loop].handler; if (lwc_string_isequal(path, about_handler_list[handler_loop].lname, &match) == lwc_error_ok && match) { break; } } if (path != NULL) lwc_string_unref(path); ctx->fetchh = fetchh; ctx->url = nsurl_ref(url); RING_INSERT(ring, ctx); return ctx; }
/** callback to set up a resource fetch context. */ static void * fetch_javascript_setup(struct fetch *fetchh, nsurl *url, bool only_2xx, bool downgrade_tls, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, const char **headers) { struct fetch_javascript_context *ctx; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->url = nsurl_ref(url); ctx->fetchh = fetchh; RING_INSERT(ring, ctx); return ctx; }
/* exported interface documented in content/fetch.h */ struct fetch * fetch_start(nsurl *url, nsurl *referer, fetch_callback callback, void *p, bool only_2xx, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, bool verifiable, bool downgrade_tls, const char *headers[]) { struct fetch *fetch; scheme_fetcher *fetcher = fetchers; lwc_string *scheme; bool match; fetch = malloc(sizeof (*fetch)); if (fetch == NULL) return NULL; /* The URL we're fetching must have a scheme */ scheme = nsurl_get_component(url, NSURL_SCHEME); assert(scheme != NULL); #ifdef DEBUG_FETCH_VERBOSE LOG(("fetch %p, url '%s'", fetch, nsurl_access(url))); #endif /* construct a new fetch structure */ fetch->callback = callback; fetch->url = nsurl_ref(url); fetch->verifiable = verifiable; fetch->p = p; fetch->http_code = 0; fetch->r_prev = NULL; fetch->r_next = NULL; fetch->referer = NULL; fetch->send_referer = false; fetch->fetcher_handle = NULL; fetch->ops = NULL; fetch->fetch_is_active = false; fetch->host = nsurl_get_component(url, NSURL_HOST); if (referer != NULL) { lwc_string *ref_scheme; fetch->referer = nsurl_ref(referer); ref_scheme = nsurl_get_component(referer, NSURL_SCHEME); /* Not a problem if referer has no scheme */ /* Determine whether to send the Referer header */ if (nsoption_bool(send_referer) && ref_scheme != NULL) { /* User permits us to send the header * Only send it if: * 1) The fetch and referer schemes match * or 2) The fetch is https and the referer is http * * This ensures that referer information is only sent * across schemes in the special case of an https * request from a page served over http. The inverse * (https -> http) should not send the referer (15.1.3) */ bool match1; bool match2; if (lwc_string_isequal(scheme, ref_scheme, &match) != lwc_error_ok) { match = false; } if (lwc_string_isequal(scheme, corestring_lwc_https, &match1) != lwc_error_ok) { match1 = false; } if (lwc_string_isequal(ref_scheme, corestring_lwc_http, &match2) != lwc_error_ok) { match2= false; } if (match == true || (match1 == true && match2 == true)) fetch->send_referer = true; } if (ref_scheme != NULL) lwc_string_unref(ref_scheme); } /* Pick the scheme ops */ while (fetcher) { if ((lwc_string_isequal(fetcher->scheme_name, scheme, &match) == lwc_error_ok) && (match == true)) { fetch->ops = fetcher; break; } fetcher = fetcher->next_fetcher; } if (fetch->ops == NULL) goto failed; /* Got a scheme fetcher, try and set up the fetch */ fetch->fetcher_handle = fetch->ops->setup_fetch(fetch, url, only_2xx, downgrade_tls, post_urlenc, post_multipart, headers); if (fetch->fetcher_handle == NULL) goto failed; /* Rah, got it, so ref the fetcher. */ fetch_ref_fetcher(fetch->ops); /* these aren't needed past here */ lwc_string_unref(scheme); /* Dump us in the queue and ask the queue to run. */ RING_INSERT(queue_ring, fetch); fetch_dispatch_jobs(); return fetch; failed: lwc_string_unref(scheme); if (fetch->host != NULL) lwc_string_unref(fetch->host); if (fetch->url != NULL) nsurl_unref(fetch->url); if (fetch->referer != NULL) nsurl_unref(fetch->referer); free(fetch); return NULL; }