/* exported interface documented in content/fetch.h */ void fetch_remove_from_queues(struct fetch *fetch) { int all_active; #ifdef DEBUG_FETCH_VERBOSE int all_queued; LOG(("Fetch %p, fetcher %p can be freed", fetch, fetch->fetcher_handle)); #endif /* Go ahead and free the fetch properly now */ if (fetch->fetch_is_active) { RING_REMOVE(fetch_ring, fetch); } else { RING_REMOVE(queue_ring, fetch); } RING_GETSIZE(struct fetch, fetch_ring, all_active); fetch_active = (all_active > 0); #ifdef DEBUG_FETCH_VERBOSE LOG(("Fetch ring is now %d elements.", all_active)); RING_GETSIZE(struct fetch, queue_ring, all_queued); LOG(("Queue ring is now %d elements.", all_queued)); #endif }
/* See hlcache.h for documentation */ nserror hlcache_handle_abort(hlcache_handle *handle) { struct hlcache_entry *entry = handle->entry; struct content *c; if (entry == NULL) { /* This handle is not yet associated with a cache entry. * The implication is that the fetch for the handle has * not progressed to the point where the entry can be * created. */ RING_ITERATE_START(struct hlcache_retrieval_ctx, hlcache->retrieval_ctx_ring, ictx) { if (ictx->handle == handle && ictx->migrate_target == false) { /* This is the nascent context for us, * so abort the fetch */ llcache_handle_abort(ictx->llcache); llcache_handle_release(ictx->llcache); /* Remove us from the ring */ RING_REMOVE(hlcache->retrieval_ctx_ring, ictx); /* Throw us away */ free((char *) ictx->child.charset); free(ictx); /* And stop */ RING_ITERATE_STOP(hlcache->retrieval_ctx_ring, ictx); } } RING_ITERATE_END(hlcache->retrieval_ctx_ring, ictx); return NSERROR_OK; }
/* See hlcache.h for documentation */ nserror hlcache_handle_release(hlcache_handle *handle) { if (handle->entry != NULL) { content_remove_user(handle->entry->content, hlcache_content_callback, handle); } else { RING_ITERATE_START(struct hlcache_retrieval_ctx, hlcache->retrieval_ctx_ring, ictx) { if (ictx->handle == handle && ictx->migrate_target == false) { /* This is the nascent context for us, * so abort the fetch */ llcache_handle_abort(ictx->llcache); llcache_handle_release(ictx->llcache); /* Remove us from the ring */ RING_REMOVE(hlcache->retrieval_ctx_ring, ictx); /* Throw us away */ free((char *) ictx->child.charset); free(ictx); /* And stop */ RING_ITERATE_STOP(hlcache->retrieval_ctx_ring, ictx); } } RING_ITERATE_END(hlcache->retrieval_ctx_ring, ictx); } handle->cb = NULL; handle->pw = NULL; free(handle); return NSERROR_OK; }
/** * Finalise a cURL fetcher. * * \param scheme The scheme to finalise. */ static void fetch_curl_finalise(lwc_string *scheme) { struct cache_handle *h; curl_fetchers_registered--; LOG("Finalise cURL fetcher %s", lwc_string_data(scheme)); if (curl_fetchers_registered == 0) { CURLMcode codem; /* All the fetchers have been finalised. */ LOG("All cURL fetchers finalised, closing down cURL"); curl_easy_cleanup(fetch_blank_curl); codem = curl_multi_cleanup(fetch_curl_multi); if (codem != CURLM_OK) LOG("curl_multi_cleanup failed: ignoring"); curl_global_cleanup(); } /* Free anything remaining in the cached curl handle ring */ while (curl_handle_ring != NULL) { h = curl_handle_ring; RING_REMOVE(curl_handle_ring, h); lwc_string_unref(h->host); curl_easy_cleanup(h->handle); free(h); } }
static void * thread_func(void *param) { thread_t *t = (thread_t *)param; while (1) { if (t->state == DONE) return NULL; task_t *task = NULL; pthread_mutex_lock(&t->task_list_lock); while (RING_EMPTY(&t->tasks, task, link)) { if (t->state == DONE) return NULL; pthread_cond_wait(&t->task_list_aval_cond, &t->task_list_lock); } task = RING_FIRST(&t->tasks); RING_REMOVE(task, link); pthread_mutex_unlock(&t->task_list_lock); if (task) { (*task->func)(&(task->param)); mem_pool_free(t->mem_pool, (void *)task); } } return NULL; }
/** callback to free a about fetch */ static void fetch_about_free(void *ctx) { struct fetch_about_context *c = ctx; nsurl_unref(c->url); RING_REMOVE(ring, c); free(ctx); }
/** callback to free a resource fetch */ static void fetch_javascript_free(void *ctx) { struct fetch_javascript_context *c = ctx; if (c->url != NULL) { nsurl_unref(c->url); } RING_REMOVE(ring, c); free(ctx); }
/** callback to free a resource fetch */ static void fetch_resource_free(void *ctx) { struct fetch_resource_context *c = ctx; if (c->redirect_url != NULL) nsurl_unref(c->redirect_url); if (c->url != NULL) nsurl_unref(c->url); RING_REMOVE(ring, c); free(ctx); }
static void fetch_data_free(void *ctx) { struct fetch_data_context *c = ctx; free(c->url); free(c->data); free(c->mimetype); RING_REMOVE(ring, c); free(ctx); }
static void fetch_rsrc_free(void *ctx) { struct fetch_rsrc_context *c = (struct fetch_rsrc_context *)ctx; free(c->name); free(c->url); free(c->data); free(c->mimetype); RING_REMOVE(ring, c); free(ctx); }
/** * Find a CURL handle to use to dispatch a job */ static CURL *fetch_curl_get_handle(lwc_string *host) { struct cache_handle *h; CURL *ret; RING_FINDBYLWCHOST(curl_handle_ring, h, host); if (h) { ret = h->handle; lwc_string_unref(h->host); RING_REMOVE(curl_handle_ring, h); free(h); } else { ret = curl_easy_duphandle(fetch_blank_curl); } return ret; }
/** * 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; } }
/** * Migrate a retrieval context into its final destination content * * \param ctx Context to migrate * \param effective_type The effective MIME type of the content, or NULL * \return NSERROR_OK on success, * NSERROR_NEED_DATA on success where data is needed, * appropriate error otherwise */ static nserror hlcache_migrate_ctx(hlcache_retrieval_ctx *ctx, lwc_string *effective_type) { content_type type = CONTENT_NONE; nserror error = NSERROR_OK; ctx->migrate_target = true; if (effective_type != NULL && hlcache_type_is_acceptable(effective_type, ctx->accepted_types, &type)) { error = hlcache_find_content(ctx, effective_type); if (error != NSERROR_OK && error != NSERROR_NEED_DATA) { if (ctx->handle->cb != NULL) { hlcache_event hlevent; hlevent.type = CONTENT_MSG_ERROR; hlevent.data.error = messages_get("MiscError"); ctx->handle->cb(ctx->handle, &hlevent, ctx->handle->pw); } llcache_handle_abort(ctx->llcache); llcache_handle_release(ctx->llcache); } } else if (type == CONTENT_NONE && (ctx->flags & HLCACHE_RETRIEVE_MAY_DOWNLOAD)) { /* Unknown type, and we can download, so convert */ llcache_handle_force_stream(ctx->llcache); if (ctx->handle->cb != NULL) { hlcache_event hlevent; hlevent.type = CONTENT_MSG_DOWNLOAD; hlevent.data.download = ctx->llcache; ctx->handle->cb(ctx->handle, &hlevent, ctx->handle->pw); } /* Ensure caller knows we need data */ error = NSERROR_NEED_DATA; } else { /* Unacceptable type: report error */ if (ctx->handle->cb != NULL) { hlcache_event hlevent; hlevent.type = CONTENT_MSG_ERROR; hlevent.data.error = messages_get("UnacceptableType"); ctx->handle->cb(ctx->handle, &hlevent, ctx->handle->pw); } llcache_handle_abort(ctx->llcache); llcache_handle_release(ctx->llcache); } ctx->migrate_target = false; /* No longer require retrieval context */ RING_REMOVE(hlcache->retrieval_ctx_ring, ctx); free((char *) ctx->child.charset); free(ctx); return error; }