/** * Callback for low-level cache events * * \param handle Low-level cache handle * \param event Event object * \param pw Our context * \return NSERROR_OK on success, appropriate error otherwise */ static nserror download_callback(llcache_handle *handle, const llcache_event *event, void *pw) { download_context *ctx = pw; nserror error = NSERROR_OK; switch (event->type) { case LLCACHE_EVENT_HAD_HEADERS: error = download_context_process_headers(ctx); if (error != NSERROR_OK) { llcache_handle_abort(handle); download_context_destroy(ctx); } break; case LLCACHE_EVENT_HAD_DATA: /* If we didn't know up-front that this fetch was for download, * then we won't receive the HAD_HEADERS event. Catch up now. */ if (ctx->window == NULL) { error = download_context_process_headers(ctx); if (error != NSERROR_OK) { llcache_handle_abort(handle); download_context_destroy(ctx); } } if (error == NSERROR_OK) { /** \todo Lose ugly cast */ error = gui_download_window_data(ctx->window, (char *) event->data.data.buf, event->data.data.len); if (error != NSERROR_OK) llcache_handle_abort(handle); } break; case LLCACHE_EVENT_DONE: assert(ctx->window != NULL); gui_download_window_done(ctx->window); break; case LLCACHE_EVENT_ERROR: if (ctx->window != NULL) gui_download_window_error(ctx->window, event->data.msg); break; case LLCACHE_EVENT_PROGRESS: break; } return error; }
/* 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; }
/** * Handler for low-level cache events * * \param llcache Low-level cache handle * \param event Event details * \param pw Pointer to our context * \return NSERROR_OK on success, appropriate error otherwise */ nserror content_llcache_callback(llcache_handle *llcache, const llcache_event *event, void *pw) { struct content *c = pw; union content_msg_data msg_data; nserror error = NSERROR_OK; switch (event->type) { case LLCACHE_EVENT_HAD_HEADERS: /* Will never happen: handled in hlcache */ break; case LLCACHE_EVENT_HAD_DATA: if (c->handler->process_data != NULL) { if (c->handler->process_data(c, (const char *) event->data.data.buf, event->data.data.len) == false) { llcache_handle_abort(c->llcache); c->status = CONTENT_STATUS_ERROR; /** \todo It's not clear what error this is */ error = NSERROR_NOMEM; } } break; case LLCACHE_EVENT_DONE: { size_t source_size; (void) llcache_handle_get_source_data(llcache, &source_size); content_set_status(c, messages_get("Processing")); msg_data.explicit_status_text = NULL; content_broadcast(c, CONTENT_MSG_STATUS, msg_data); content_convert(c); } break; case LLCACHE_EVENT_ERROR: /** \todo Error page? */ c->status = CONTENT_STATUS_ERROR; msg_data.error = event->data.msg; content_broadcast(c, CONTENT_MSG_ERROR, msg_data); break; case LLCACHE_EVENT_PROGRESS: content_set_status(c, event->data.msg); msg_data.explicit_status_text = NULL; content_broadcast(c, CONTENT_MSG_STATUS, msg_data); break; case LLCACHE_EVENT_REDIRECT: msg_data.redirect.from = event->data.redirect.from; msg_data.redirect.to = event->data.redirect.to; content_broadcast(c, CONTENT_MSG_REDIRECT, msg_data); break; } return error; }
/** * Abort a content object * * \param c The content object to abort * \return NSERROR_OK on success, otherwise appropriate error */ nserror content_abort(struct content *c) { LOG("Aborting %p", c); if (c->handler->stop != NULL) c->handler->stop(c); /* And for now, abort our llcache object */ return llcache_handle_abort(c->llcache); }
/** * 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; }
/* See download.h for documentation */ void download_context_abort(download_context *ctx) { llcache_handle_abort(ctx->llcache); }