netsurf/desktop/fetch.c

212 lines
5.0 KiB
C

/**
* $Id: fetch.c,v 1.7 2003/01/06 00:04:43 bursa Exp $
*/
#include "libxml/HTMLparser.h"
#include "netsurf/render/box.h"
#include "netsurf/render/css.h"
#include "netsurf/desktop/browser.h"
#include "netsurf/desktop/netsurf.h"
#include "netsurf/desktop/fetch.h"
#include "netsurf/render/utils.h"
#include "netsurf/utils/log.h"
#include "curl/curl.h"
#include <time.h>
#include <string.h>
#include <stdio.h>
struct fetch* create_fetch(char* location, char* previous, fetch_flags f, struct fetch_request* r)
{
struct fetch* fetch = (struct fetch*) xcalloc(1, sizeof(struct fetch));
if (fetch->location != NULL)
free(fetch->location);
fetch->location = xstrdup(location);
fetch->type = fetch_CURL;
fetch->flags = f;
fetch->status = fetch_STATUS_WAIT;
fetch->bytes_fetched = 0;
fetch->bytes_total = -1;
fetch->request = r;
fetch->start_time = time(&fetch->start_time);
fetch->next = netsurf_fetches;
netsurf_fetches = fetch;
return fetch;
}
void fetch_destroy(struct fetch* f)
{
if (f == NULL)
return;
if (netsurf_fetches == f)
netsurf_fetches = f->next;
else
{
struct fetch* ff = netsurf_fetches;
while (ff->next != f && ff->next != NULL)
ff = ff->next;
if (ff->next == f)
ff->next = f->next;
}
xfree(f->location);
xfree(f->request);
xfree(f);
}
struct fetch* fetch_cancel(struct fetch* f)
{
if (f == NULL)
return NULL;
/* may need to contact server here */
f->status = fetch_DELETED;
/* fetch may not necessarily be destroyed if the cancelling can't be done
instantly */
return f;
}
void fetch_receive(struct fetch* f, int amount, char* bytes)
{
struct browser_message msg;
f->bytes_fetched = f->bytes_fetched + amount;
switch (f->request->type)
{
case REQUEST_FROM_BROWSER:
msg.type = msg_FETCH_DATA;
msg.f = f;
msg.data.fetch_data.block = bytes;
msg.data.fetch_data.block_size = amount;
if (browser_window_message(f->request->requestor.browser, &msg) != 0)
{
fetch_cancel(f);
return;
}
break;
default:
break;
}
if (f->bytes_fetched >= f->bytes_total && f->bytes_total != -1)
{
msg.type = msg_FETCH_FINISHED;
msg.f = f;
browser_window_message(f->request->requestor.browser, &msg);
fetch_destroy(f);
}
return;
}
size_t fetch_curl_data(void * data, size_t size, size_t nmemb, struct fetch* f)
{
struct browser_message msg;
msg.type = msg_FETCH_DATA;
msg.f = f;
msg.data.fetch_data.block = data;
msg.data.fetch_data.block_size = size * nmemb;
LOG(("sending curl's FETCH_DATA to browser"));
browser_window_message(f->request->requestor.browser, &msg);
return size * nmemb;
}
struct fetch* fetch_poll(struct fetch* f)
{
struct fetch* ret = f;
/* LOG(("polling...")); */
if (f == NULL)
{
/* LOG(("null fetch; returning")); */
return f;
}
if (f->status == fetch_DELETED)
{
ret = f->next;
LOG(("deleting marked fetch"));
fetch_destroy(f);
LOG(("moving on..."));
return fetch_poll(ret);
}
else if (f->type == fetch_CURL && f->status == fetch_STATUS_WAIT)
{
struct browser_message msg;
CURL* curl;
LOG(("init curl"));
curl = curl_easy_init();
LOG(("init curl returned"));
if (curl != 0)
{
LOG(("init curl OK"));
/* shouldn't assume this! somehow work it out instead. */
msg.type = msg_FETCH_FETCH_INFO;
msg.f = f;
msg.data.fetch_info.type = type_HTML;
msg.data.fetch_info.total_size = -1;
if (browser_window_message(f->request->requestor.browser, &msg) == 0)
{
LOG(("about to set options"));
curl_easy_setopt(curl, CURLOPT_URL, f->location);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fetch_curl_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, f);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "NetSurf/0.00 (alpha)");
LOG(("about to perform"));
curl_easy_perform(curl);
LOG(("about to cleanup"));
curl_easy_cleanup(curl);
LOG(("cleanup finished"));
msg.type = msg_FETCH_FINISHED;
msg.f = f;
LOG(("sending FETCH_FINISHED to browser"));
browser_window_message(f->request->requestor.browser, &msg);
LOG(("FETCH_FINISHED accepted"));
ret = f->next;
LOG(("Destroying f"));
fetch_destroy(f);
LOG(("Moving on..."));
return fetch_poll(ret);
}
LOG(("about to cleanup since requestor went funny"));
curl_easy_cleanup(curl);
LOG(("Requesting browser didn't like something"));
ret = f->next;
LOG(("Cancelling fetch"));
f = fetch_cancel(f);
return fetch_poll(ret);
}
LOG(("we are aborting the mission"));
msg.type = msg_FETCH_ABORT;
msg.f = f;
browser_window_message(f->request->requestor.browser, &msg);
LOG(("ABORT message sent to browser"));
ret = f->next;
fetch_destroy(f);
return fetch_poll(ret); /* carry on polling */
}
LOG(("Moving on (at end of function with f->next)"));
f->next = fetch_poll(f->next);
return f;
}