diff options
author | John Mark Bell <jmb@netsurf-browser.org> | 2010-04-04 12:41:19 +0000 |
---|---|---|
committer | John Mark Bell <jmb@netsurf-browser.org> | 2010-04-04 12:41:19 +0000 |
commit | 79ce683b4e6d34fe327b00f1e427e476016cfab0 (patch) | |
tree | 2ed3ba800e8f570000f97588ce668eb47168565a /content/llcache.c | |
parent | 3daffe3d6b07be7bbeedbcb2586f11edd872cbd6 (diff) | |
download | netsurf-79ce683b4e6d34fe327b00f1e427e476016cfab0.tar.gz netsurf-79ce683b4e6d34fe327b00f1e427e476016cfab0.tar.bz2 |
Most of a stop implementation.
Remaining work:
1) Clone content_html_data
2) Cloning content_css_data requires the charset of the old content
3) Calling hlcache_handle_abort() before a content has been created must clean up the retrieval context.
svn path=/trunk/netsurf/; revision=10236
Diffstat (limited to 'content/llcache.c')
-rw-r--r-- | content/llcache.c | 179 |
1 files changed, 146 insertions, 33 deletions
diff --git a/content/llcache.c b/content/llcache.c index 49556b1fe..94df0f6e5 100644 --- a/content/llcache.c +++ b/content/llcache.c @@ -172,6 +172,9 @@ static nserror llcache_object_remove_from_list(llcache_object *object, static nserror llcache_object_notify_users(llcache_object *object); +static nserror llcache_object_snapshot(llcache_object *object, + llcache_object **snapshot); + static nserror llcache_clean(void); static nserror llcache_post_data_clone(const llcache_post_data *orig, @@ -302,6 +305,66 @@ nserror llcache_handle_release(llcache_handle *handle) } /* See llcache.h for documentation */ +nserror llcache_handle_clone(llcache_handle *handle, llcache_handle **result) +{ + nserror error; + llcache_object_user *newuser; + + error = llcache_object_user_new(handle->cb, handle->pw, &newuser); + if (error == NSERROR_OK) { + llcache_object_add_user(handle->object, newuser); + newuser->handle.state = handle->state; + *result = &newuser->handle; + } + + return error; +} + +/* See llcache.h for documentation */ +nserror llcache_handle_abort(llcache_handle *handle) +{ + llcache_object_user *user = (llcache_object_user *) handle; + llcache_object *object = handle->object, *newobject; + nserror error = NSERROR_OK; + bool all_alone = true; + + /* Determine if we are the only user */ + if (user->prev != NULL) + all_alone = false; + if (user->next != NULL) + all_alone = false; + + if (all_alone == false) { + /* We must snapshot this object */ + error = llcache_object_snapshot(object, &newobject); + if (error != NSERROR_OK) + return error; + /* Move across to the new object */ + llcache_object_remove_user(object, user); + llcache_object_add_user(newobject, user); + + /* Add new object to uncached list */ + llcache_object_add_to_list(object, &llcache_uncached_objects); + + /* And use it from now on. */ + object = newobject; + } else { + /* We're the only user, so abort any fetch in progress */ + if (object->fetch.fetch != NULL) { + fetch_abort(object->fetch.fetch); + object->fetch.fetch = NULL; + } + + object->fetch.state = LLCACHE_FETCH_COMPLETE; + + /* Invalidate cache control data */ + memset(&(object->cache), 0, sizeof(llcache_cache_control)); + } + + return error; +} + +/* See llcache.h for documentation */ const char *llcache_handle_get_url(const llcache_handle *handle) { return handle->object != NULL ? handle->object->url : NULL; @@ -1033,8 +1096,7 @@ nserror llcache_object_notify_users(llcache_object *object) for (user = object->users; user != NULL; user = next_user) { /* Emit necessary events to bring the user up-to-date */ llcache_handle *handle = &user->handle; - llcache_fetch_state hstate = handle->state; - llcache_fetch_state objstate = object->fetch.state; + const llcache_fetch_state objstate = object->fetch.state; /* Save identity of next user in case client destroys * the user underneath us */ @@ -1042,20 +1104,22 @@ nserror llcache_object_notify_users(llcache_object *object) next_user = user->next; #ifdef LLCACHE_TRACE - if (hstate != objstate) + if (handle->state != objstate) LOG(("User %p state: %d Object state: %d", - user, hstate, objstate)); + user, handle->state, objstate)); #endif /* User: INIT, Obj: HEADERS, DATA, COMPLETE => User->HEADERS */ - if (hstate == LLCACHE_FETCH_INIT && + if (handle->state == LLCACHE_FETCH_INIT && objstate > LLCACHE_FETCH_INIT) { - hstate = LLCACHE_FETCH_HEADERS; + handle->state = LLCACHE_FETCH_HEADERS; } /* User: HEADERS, Obj: DATA, COMPLETE => User->DATA */ - if (hstate == LLCACHE_FETCH_HEADERS && + if (handle->state == LLCACHE_FETCH_HEADERS && objstate > LLCACHE_FETCH_HEADERS) { + handle->state = LLCACHE_FETCH_DATA; + /* Emit HAD_HEADERS event */ event.type = LLCACHE_EVENT_HAD_HEADERS; @@ -1069,20 +1133,21 @@ nserror llcache_object_notify_users(llcache_object *object) llcache_object_user_destroy(user); continue; } - - hstate = LLCACHE_FETCH_DATA; } /* User: DATA, Obj: DATA, COMPLETE, more source available */ - if (hstate == LLCACHE_FETCH_DATA && + if (handle->state == LLCACHE_FETCH_DATA && objstate >= LLCACHE_FETCH_DATA && object->source_len > handle->bytes) { + size_t oldbytes = handle->bytes; + + /* Update record of last byte emitted */ + handle->bytes = object->source_len; + /* Emit HAD_DATA event */ event.type = LLCACHE_EVENT_HAD_DATA; - event.data.data.buf = - object->source_data + handle->bytes; - event.data.data.len = - object->source_len - handle->bytes; + event.data.data.buf = object->source_data + oldbytes; + event.data.data.len = object->source_len - oldbytes; error = handle->cb(handle, &event, handle->pw); if (error != NSERROR_OK) { @@ -1094,14 +1159,13 @@ nserror llcache_object_notify_users(llcache_object *object) llcache_object_user_destroy(user); continue; } - - /* Update record of last byte emitted */ - handle->bytes = object->source_len; } /* User: DATA, Obj: COMPLETE => User->COMPLETE */ - if (hstate == LLCACHE_FETCH_DATA && + if (handle->state == LLCACHE_FETCH_DATA && objstate > LLCACHE_FETCH_DATA) { + handle->state = LLCACHE_FETCH_COMPLETE; + /* Emit DONE event */ event.type = LLCACHE_EVENT_DONE; @@ -1115,21 +1179,80 @@ nserror llcache_object_notify_users(llcache_object *object) llcache_object_user_destroy(user); continue; } - - hstate = LLCACHE_FETCH_COMPLETE; } /* No longer the target of an iterator */ user->iterator_target = false; - - /* Sync handle's state with reality */ - handle->state = hstate; } return NSERROR_OK; } /** + * Make a snapshot of the current state of an llcache_object. + * + * This has the side-effect of the new object being non-cacheable, + * also not-fetching and not a candidate for any other object. + * + * Also note that this new object has no users and at least one + * should be assigned to it before llcache_clean is entered or it + * will be immediately cleaned up. + * + * \param object The object to take a snapshot of + * \param snapshot Pointer to receive snapshot of \a object + * \return NSERROR_OK on success, appropriate error otherwise + */ +nserror llcache_object_snapshot(llcache_object *object, + llcache_object **snapshot) +{ + llcache_object *newobj; + nserror error; + + error = llcache_object_new(object->url, &newobj); + + if (error != NSERROR_OK) + return error; + + newobj->has_query = object->has_query; + + newobj->source_alloc = newobj->source_len = object->source_len; + + if (object->source_len > 0) { + newobj->source_data = malloc(newobj->source_alloc); + if (newobj->source_data == NULL) { + llcache_object_destroy(newobj); + return NSERROR_NOMEM; + } + memcpy(newobj->source_data, object->source_data, newobj->source_len); + } + + if (object->num_headers > 0) { + newobj->headers = calloc(sizeof(llcache_header), object->num_headers); + if (newobj->headers == NULL) { + llcache_object_destroy(newobj); + return NSERROR_NOMEM; + } + while (newobj->num_headers < object->num_headers) { + llcache_header *nh = &(newobj->headers[newobj->num_headers]); + llcache_header *oh = &(object->headers[newobj->num_headers]); + newobj->num_headers += 1; + nh->name = strdup(oh->name); + nh->value = strdup(oh->value); + if (nh->name == NULL || nh->value == NULL) { + llcache_object_destroy(newobj); + return NSERROR_NOMEM; + } + } + } + + newobj->fetch.state = LLCACHE_FETCH_COMPLETE; + + *snapshot = newobj; + + return NSERROR_OK; +} + +/** * Attempt to clean the cache * * \return NSERROR_OK. @@ -1376,16 +1499,6 @@ void llcache_fetch_callback(fetch_msg msg, void *p, const void *data, } return; } - - /* Keep users in sync with reality */ - error = llcache_object_notify_users(object); - if (error != NSERROR_OK) { - /** \todo Error handling */ - if (object->fetch.fetch != NULL) { - fetch_abort(object->fetch.fetch); - object->fetch.fetch = NULL; - } - } } /** |