2002-09-11 18:24:02 +04:00
|
|
|
/**
|
2002-12-26 00:38:45 +03:00
|
|
|
* $Id: fetch.c,v 1.5 2002/12/25 21:38:45 bursa Exp $
|
2002-09-11 18:24:02 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#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 "curl/curl.h"
|
|
|
|
#include <time.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
void fetch_identify_location(struct fetch* f, char* location, char* previous)
|
|
|
|
{
|
|
|
|
if (f->location != NULL)
|
|
|
|
xfree(f->location);
|
|
|
|
|
2002-12-26 00:38:45 +03:00
|
|
|
f->location = xstrdup(location);
|
|
|
|
|
|
|
|
if (strspn(location, "file:/") == strlen("file:/"))
|
2002-09-11 18:24:02 +04:00
|
|
|
f->type = fetch_FILE;
|
2002-12-26 00:38:45 +03:00
|
|
|
else
|
|
|
|
/* throw everything else at curl, since it can fetch lots of protocols */
|
2002-12-25 23:17:18 +03:00
|
|
|
f->type = fetch_CURL;
|
2002-09-11 18:24:02 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
fetch_identify_location(fetch, location, previous);
|
|
|
|
|
|
|
|
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("fetch_poll","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("fetch_poll","polling...");
|
|
|
|
|
|
|
|
if (f == NULL)
|
|
|
|
{
|
|
|
|
Log("fetch_poll","null fetch; returning");
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f->type == fetch_DELETED)
|
|
|
|
{
|
|
|
|
ret = f->next;
|
|
|
|
Log("fetch_poll", "deleting marked fetch");
|
|
|
|
fetch_destroy(f);
|
|
|
|
Log("fetch_poll", "moving on...");
|
|
|
|
return fetch_poll(ret);
|
|
|
|
}
|
|
|
|
else if (f->type == fetch_CURL && f->status == fetch_STATUS_WAIT)
|
|
|
|
{
|
|
|
|
struct browser_message msg;
|
|
|
|
CURL* curl;
|
|
|
|
|
|
|
|
Log("fetch_poll","init curl");
|
|
|
|
curl = curl_easy_init();
|
|
|
|
Log("fetch_poll","init curl returned");
|
|
|
|
if (curl != 0)
|
|
|
|
{
|
|
|
|
Log("fetch_poll","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("fetch_poll","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);
|
2002-09-18 23:30:19 +04:00
|
|
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, "NetSurf");
|
2002-09-11 18:24:02 +04:00
|
|
|
Log("fetch_poll","about to perform");
|
|
|
|
curl_easy_perform(curl);
|
|
|
|
Log("fetch_poll","about to cleanup");
|
|
|
|
curl_easy_cleanup(curl);
|
|
|
|
|
|
|
|
Log("fetch_poll","cleanup finished");
|
|
|
|
msg.type = msg_FETCH_FINISHED;
|
|
|
|
msg.f = f;
|
|
|
|
Log("fetch_poll","sending FETCH_FINISHED to browser");
|
|
|
|
browser_window_message(f->request->requestor.browser, &msg);
|
|
|
|
Log("fetch_poll","FETCH_FINISHED accepted");
|
|
|
|
|
|
|
|
ret = f->next;
|
|
|
|
Log("fetch_poll","Destroying f");
|
|
|
|
fetch_destroy(f);
|
|
|
|
Log("fetch_poll","Moving on...");
|
|
|
|
return fetch_poll(ret);
|
|
|
|
}
|
|
|
|
Log("fetch_poll","about to cleanup since requestor went funny");
|
|
|
|
curl_easy_cleanup(curl);
|
|
|
|
|
|
|
|
Log("fetch_poll","Requesting browser didn't like something");
|
|
|
|
ret = f->next;
|
|
|
|
Log("fetch_poll","Cancelling fetch");
|
|
|
|
f = fetch_cancel(f);
|
|
|
|
return fetch_poll(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
Log("fetch_poll","we are aborting the mission");
|
|
|
|
msg.type = msg_FETCH_ABORT;
|
|
|
|
msg.f = f;
|
|
|
|
browser_window_message(f->request->requestor.browser, &msg);
|
|
|
|
Log("fetch_poll","ABORT message sent to browser");
|
|
|
|
|
|
|
|
ret = f->next;
|
|
|
|
fetch_destroy(f);
|
|
|
|
return fetch_poll(ret); /* carry on polling */
|
|
|
|
}
|
|
|
|
else if (f->type == fetch_FILE && f->status == fetch_STATUS_WAIT)
|
|
|
|
{
|
|
|
|
struct browser_message msg;
|
|
|
|
char actual_filename[1024];
|
|
|
|
FILE* in;
|
|
|
|
|
|
|
|
gui_file_to_filename(f->location, actual_filename, 1024);
|
2002-12-25 23:17:18 +03:00
|
|
|
/* in = fopen("files","a");
|
2002-09-11 18:24:02 +04:00
|
|
|
fprintf(in, "%s\n%s\n\n",f->location, actual_filename);
|
2002-12-25 23:17:18 +03:00
|
|
|
fclose(in);*/
|
2002-09-11 18:24:02 +04:00
|
|
|
in = fopen(actual_filename, "r");
|
|
|
|
|
|
|
|
if (in == NULL)
|
|
|
|
{
|
|
|
|
/* can't open file -- send abort to requestor, then destroy */
|
|
|
|
Log("fetch_poll","can't open file");
|
|
|
|
msg.type = msg_FETCH_ABORT;
|
|
|
|
msg.f = f;
|
|
|
|
browser_window_message(f->request->requestor.browser, &msg);
|
|
|
|
Log("fetch_poll","ABORT message sent to browser");
|
|
|
|
|
|
|
|
ret = f->next;
|
|
|
|
fetch_destroy(f);
|
|
|
|
Log("fetch_poll","destroyed f; moving on");
|
|
|
|
|
|
|
|
return fetch_poll(ret); /* carry on polling */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* file opened successfully. now to send size and type to requestor,
|
|
|
|
then the data, then finish. */
|
|
|
|
int size;
|
|
|
|
|
|
|
|
/* calculate size */
|
|
|
|
Log("fetch_poll","calculating file size");
|
|
|
|
fseek(in, 0, SEEK_END);
|
|
|
|
size = (int) ftell(in);
|
|
|
|
fclose(in);
|
|
|
|
|
|
|
|
/* send file info. (assuming HTML at the mo, but should work out
|
|
|
|
what it is, somehow) */
|
|
|
|
msg.type = msg_FETCH_FETCH_INFO;
|
|
|
|
msg.f = f;
|
|
|
|
msg.data.fetch_info.type = type_HTML;
|
|
|
|
msg.data.fetch_info.total_size = size;
|
|
|
|
|
|
|
|
Log("fetch_poll","sending FETCH_INFO to browser");
|
|
|
|
if (browser_window_message(f->request->requestor.browser, &msg) == 0)
|
|
|
|
{
|
|
|
|
/* file info accepted. can now load the data and send it */
|
|
|
|
Log("fetch_poll","FETCH_INFO accepted");
|
|
|
|
f->status = fetch_STATUS_FETCH;
|
|
|
|
|
|
|
|
/* load and send data */
|
|
|
|
msg.type = msg_FETCH_DATA;
|
|
|
|
msg.f = f;
|
|
|
|
msg.data.fetch_data.block = load(actual_filename);
|
|
|
|
msg.data.fetch_data.block_size = size;
|
|
|
|
Log("fetch_poll","sending FETCH_DATA to browser");
|
|
|
|
if (browser_window_message(f->request->requestor.browser, &msg) == 0)
|
|
|
|
{
|
|
|
|
xfree(msg.data.fetch_data.block);
|
|
|
|
/* data accepted. no more data, so finish */
|
|
|
|
Log("fetch_poll","FETCH_DATA accepted");
|
|
|
|
f->status = fetch_STATUS_FINISH;
|
|
|
|
|
|
|
|
/* send finish */
|
|
|
|
msg.type = msg_FETCH_FINISHED;
|
|
|
|
msg.f = f;
|
|
|
|
Log("fetch_poll","sending FETCH_FINISHED to browser");
|
|
|
|
browser_window_message(f->request->requestor.browser, &msg);
|
|
|
|
Log("fetch_poll","FETCH_FINISHED accepted");
|
|
|
|
|
|
|
|
ret = f->next;
|
|
|
|
Log("fetch_poll","Destroying f");
|
|
|
|
fetch_destroy(f);
|
|
|
|
Log("fetch_poll","Moving on...");
|
|
|
|
return fetch_poll(ret);
|
|
|
|
/* destroy this fetch, then move on to next fetch to poll */
|
|
|
|
}
|
|
|
|
xfree(msg.data.fetch_data.block);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* requestor didn't like something, and wants the fetch cancelled */
|
|
|
|
Log("fetch_poll","Requesting browser didn't like something");
|
|
|
|
ret = f->next;
|
|
|
|
Log("fetch_poll","Cancelling fetch");
|
|
|
|
f = fetch_cancel(f);
|
|
|
|
return fetch_poll(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Log("fetch_poll","Moving on (at end of function with f->next)");
|
|
|
|
f->next = fetch_poll(f->next);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|