summaryrefslogtreecommitdiff
path: root/desktop/fetch.c
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/fetch.c')
-rw-r--r--desktop/fetch.c344
1 files changed, 344 insertions, 0 deletions
diff --git a/desktop/fetch.c b/desktop/fetch.c
new file mode 100644
index 000000000..a7881fcc2
--- /dev/null
+++ b/desktop/fetch.c
@@ -0,0 +1,344 @@
+/**
+ * $Id: fetch.c,v 1.1 2002/09/11 14:24:02 monkeyson 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 "curl/curl.h"
+#include <time.h>
+#include <string.h>
+#include <stdio.h>
+
+void fetch_identify_location(struct fetch* f, char* location, char* previous)
+{
+ FILE* ff = fopen("identify", "a");
+ fprintf(ff, "identify: '%s' '%s'", location, previous);
+ if (f->location != NULL)
+ fprintf(ff, " '%s'\n", f->location);
+ else
+ fprintf(ff, "\n");
+ fclose(ff);
+
+ if (f->location != NULL)
+ xfree(f->location);
+
+ if (strspn(location, "http://") == strlen("http://"))
+ {
+ f->location = xstrdup(location);
+ f->type = fetch_CURL;
+ return;
+ }
+ else if (strspn(location, "file:/") == strlen("file:/"))
+ {
+ f->location = xstrdup(location);
+ f->type = fetch_FILE;
+ return;
+ }
+ else if (previous != NULL)
+ {
+ char* ext = strrchr(previous, '/');
+
+ if (ext != NULL && ext != previous)
+ {
+ int len = (int)(ext - previous) + strlen(location) + 2;
+ char* combined = xcalloc(len, sizeof(char));
+ strncpy(combined, previous, (int)(ext - previous));
+ strcpy(combined + (ext - previous), "/");
+ strcpy(combined + (ext - previous) + 1, location);
+ fetch_identify_location(f, combined, NULL);
+ xfree(combined);
+ return;
+ }
+ }
+
+ f->location = xcalloc(strlen(location) + strlen("http://") + 1, sizeof(char));
+ sprintf(f->location, "http://%s", location);
+ f->type = fetch_CURL;
+ return;
+}
+
+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);
+ 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);
+ in = fopen("files","a");
+ fprintf(in, "%s\n%s\n\n",f->location, actual_filename);
+ fclose(in);
+ 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;
+}
+