Subversion Repositories Kolibri OS

Rev

Rev 3620 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2006 Daniel Silverstone <dsilvers@digital-scurf.org>
  3.  * Copyright 2007 James Bursa <bursa@users.sourceforge.net>
  4.  * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
  5.  *
  6.  * This file is part of NetSurf.
  7.  *
  8.  * NetSurf is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; version 2 of the License.
  11.  *
  12.  * NetSurf is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19.  */
  20.  
  21. /** \file
  22.  * Fetching of data from a URL (implementation).
  23.  *
  24.  * This implementation uses libcurl's 'multi' interface.
  25.  *
  26.  *
  27.  * The CURL handles are cached in the curl_handle_ring. There are at most
  28.  * ::max_cached_fetch_handles in this ring.
  29.  */
  30.  
  31. #include <assert.h>
  32. #include <errno.h>
  33. #include <inttypes.h>
  34. #include <stdbool.h>
  35. #include <string.h>
  36. #include <strings.h>
  37. #include <time.h>
  38. #include <sys/stat.h>
  39.  
  40. #include <libwapcaplet/libwapcaplet.h>
  41.  
  42. #include "utils/config.h"
  43. //#include <openssl/ssl.h>
  44. #include "content/fetch.h"
  45. #include "content/fetchers/curl.h"
  46. #include "content/urldb.h"
  47. #include "desktop/netsurf.h"
  48. #include "desktop/options.h"
  49. #include "utils/log.h"
  50. #include "utils/messages.h"
  51. #include "utils/schedule.h"
  52. #include "utils/utils.h"
  53. #include "utils/ring.h"
  54. #include "utils/useragent.h"
  55.  
  56. /* BIG FAT WARNING: This is here because curl doesn't give you an FD to
  57.  * poll on, until it has processed a bit of the handle.  So we need schedules
  58.  * in order to make this work.
  59.  */
  60. #include <desktop/browser.h>
  61.  
  62. /* uncomment this to use scheduler based calling
  63. #define FETCHER_CURLL_SCHEDULED 1
  64. */
  65.  
  66.  
  67. struct fetch_curl_context {
  68.         struct fetch_curl_context *r_next, *r_prev;
  69.  
  70.         struct fetch *fetchh; /**< Handle for this fetch */
  71.  
  72.         bool aborted; /**< Flag indicating fetch has been aborted */
  73.         bool locked; /**< Flag indicating entry is already entered */
  74.  
  75.         nsurl *url; /**< The full url the fetch refers to */
  76.         char *path; /**< The actual path to be used with open() */
  77.  
  78.         time_t file_etag; /**< Request etag for file (previous st.m_time) */
  79. };
  80.  
  81. static struct fetch_curl_context *ring = NULL;
  82.  
  83.  
  84. static bool fetch_curl_initialise(lwc_string *scheme); //here
  85. static void fetch_curl_finalise(lwc_string *scheme); //here
  86. static bool fetch_curl_can_fetch(const nsurl *url); //here
  87. static void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url,
  88.                  bool only_2xx, bool downgrade_tls, const char *post_urlenc,
  89.                  const struct fetch_multipart_data *post_multipart,
  90.                  const char **headers); //here
  91. static bool fetch_curl_start(void *vfetch); //here
  92.  
  93. static void fetch_curl_abort(void *vf); //here
  94. static void fetch_curl_free(void *f); //here
  95. static void fetch_curl_poll(lwc_string *scheme_ignored); //here
  96.  
  97.  
  98. /**
  99.  * Initialise the fetcher.
  100.  *
  101.  * Must be called once before any other function.
  102.  */
  103.  
  104. void fetch_curl_register(void)
  105. {
  106.  
  107. lwc_string *scheme;
  108.  
  109.  
  110. LOG(("curl register\n"));
  111.  
  112. lwc_intern_string("http", SLEN("http"), &scheme);
  113.  
  114.         if (!fetch_add_fetcher(scheme,
  115.                                 fetch_curl_initialise, //here
  116.                                 fetch_curl_can_fetch, //here
  117.                                 fetch_curl_setup,
  118.                                 fetch_curl_start,
  119.                                 fetch_curl_abort, //here
  120.                                 fetch_curl_free, //here
  121. #ifdef FETCHER_CURLL_SCHEDULED
  122.                                        NULL,
  123. #else
  124.                                 fetch_curl_poll, //here
  125. #endif
  126.                                 fetch_curl_finalise)) {  //here
  127.                         LOG(("Unable to register cURL fetcher for HTTP"));
  128.                 }
  129.                
  130.                
  131.                 lwc_intern_string("https", SLEN("https"), &scheme);
  132.  
  133.         if (!fetch_add_fetcher(scheme,
  134.                                 fetch_curl_initialise,
  135.                                 fetch_curl_can_fetch,
  136.                                 fetch_curl_setup,
  137.                                 fetch_curl_start,
  138.                                 fetch_curl_abort,
  139.                                 fetch_curl_free,
  140. #ifdef FETCHER_CURLL_SCHEDULED
  141.                                        NULL,
  142. #else
  143.                                 fetch_curl_poll,
  144. #endif
  145.                                 fetch_curl_finalise)) {
  146.                         LOG(("Unable to register cURL fetcher for HTTPS"));
  147.                 }
  148.  
  149. }
  150.  
  151.  
  152. /**
  153.  * Initialise a cURL fetcher.
  154.  */
  155.  
  156. bool fetch_curl_initialise(lwc_string *scheme)
  157. {
  158.  
  159. LOG(("curl initi lwc\n"));
  160.         return true; /* Always succeeds */
  161. }
  162.  
  163.  
  164. /**
  165.  * Finalise a cURL fetcher
  166.  */
  167.  
  168. void fetch_curl_finalise(lwc_string *scheme)
  169. {
  170. LOG(("curl finali\n"));
  171. }
  172.  
  173. static bool fetch_curl_can_fetch(const nsurl *url)
  174. {
  175.         LOG(("curl can fetch\n"));
  176.         return true; //let's lie a bit
  177. }
  178.  
  179. /**
  180.  * Start fetching data for the given URL.
  181.  *
  182.  * The function returns immediately. The fetch may be queued for later
  183.  * processing.
  184.  *
  185.  * A pointer to an opaque struct curl_fetch_info is returned, which can be
  186.  * passed to fetch_abort() to abort the fetch at any time. Returns 0 if memory
  187.  * is exhausted (or some other fatal error occurred).
  188.  *
  189.  * The caller must supply a callback function which is called when anything
  190.  * interesting happens. The callback function is first called with msg
  191.  * FETCH_HEADER, with the header in data, then one or more times
  192.  * with FETCH_DATA with some data for the url, and finally with
  193.  * FETCH_FINISHED. Alternatively, FETCH_ERROR indicates an error occurred:
  194.  * data contains an error message. FETCH_REDIRECT may replace the FETCH_HEADER,
  195.  * FETCH_DATA, FETCH_FINISHED sequence if the server sends a replacement URL.
  196.  *
  197.  * Some private data can be passed as the last parameter to fetch_start, and
  198.  * callbacks will contain this.
  199.  */
  200.  
  201. void * fetch_curl_setup (struct fetch *fetchh,
  202.                  nsurl *url,
  203.                  bool only_2xx,
  204.                  bool downgrade_tls,
  205.                  const char *post_urlenc,
  206.                  const struct fetch_multipart_data *post_multipart,
  207.                  const char **headers)
  208. {
  209.  
  210.         LOG(("curl setup\n"));
  211.        
  212.         struct fetch_curl_context *ctx;
  213.         int i;
  214.  
  215.         ctx = calloc(1, sizeof(*ctx));
  216.         if (ctx == NULL)
  217.                 return NULL;
  218.  
  219.         //ctx->path = url_to_path(nsurl_access(url));
  220.         char *zz;
  221.         int pr;
  222.         nsurl_get(url, NSURL_WITH_FRAGMENT, &zz, &pr);
  223.        
  224.         ctx->path = zz;
  225.         if (ctx->path == NULL) {
  226.                 free(ctx);
  227.                 return NULL;
  228.         }
  229.  
  230.         ctx->url = nsurl_ref(url);
  231.  
  232.  
  233.         ctx->fetchh = fetchh;
  234.  
  235.         RING_INSERT(ring, ctx);
  236.  
  237.         return ctx;
  238. }
  239.  
  240.  
  241. /**
  242.  * Dispatch a single job
  243.  */
  244. bool fetch_curl_start(void *vfetch)
  245. {
  246. LOG(("curl start\n"));
  247.         return true;
  248. }
  249.  
  250.  
  251.  
  252.  
  253.  
  254.  
  255. /**
  256.  * Abort a fetch.
  257.  */
  258.  
  259. void fetch_curl_abort(void *ctx)
  260. {
  261.         struct fetch_curl_context *c = ctx;
  262.  
  263.         /* To avoid the poll loop having to deal with the fetch context
  264.          * disappearing from under it, we simply flag the abort here.
  265.          * The poll loop itself will perform the appropriate cleanup.
  266.          */
  267.         c->aborted = true;
  268. }
  269.  
  270.  
  271. /**
  272.  * Free a fetch structure and associated resources.
  273.  */
  274.  
  275. void fetch_curl_free(void *ctx)
  276. {
  277.         struct fetch_curl_context *c = ctx;
  278.         nsurl_unref(c->url);
  279.         free(c->path);
  280.         RING_REMOVE(ring, c);
  281.         free(ctx);
  282. }
  283.  
  284. static inline bool fetch_curl_send_callback(const fetch_msg *msg,
  285.                 struct fetch_curl_context *ctx)
  286. {
  287.         ctx->locked = true;
  288.         fetch_send_callback(msg, ctx->fetchh);
  289.         ctx->locked = false;
  290.  
  291.         return ctx->aborted;
  292. }
  293.  
  294. static bool fetch_curl_send_header(struct fetch_curl_context *ctx,
  295.                 const char *fmt, ...)
  296. {
  297.         fetch_msg msg;
  298.         char header[64];
  299.         va_list ap;
  300.  
  301.         va_start(ap, fmt);
  302.  
  303.         vsnprintf(header, sizeof header, fmt, ap);
  304.  
  305.         va_end(ap);
  306.  
  307.         msg.type = FETCH_HEADER;
  308.         msg.data.header_or_data.buf = (const uint8_t *) header;
  309.         msg.data.header_or_data.len = strlen(header);
  310.         fetch_curl_send_callback(&msg, ctx);
  311.  
  312.         return ctx->aborted;
  313. }
  314.  
  315. static void fetch_curl_process_error(struct fetch_curl_context *ctx, int code)
  316. {
  317.         fetch_msg msg;
  318.         char buffer[1024];
  319.         const char *title;
  320.         char key[8];
  321.  
  322.         /* content is going to return error code */
  323.         fetch_set_http_code(ctx->fetchh, code);
  324.  
  325.         /* content type */
  326.         if (fetch_curl_send_header(ctx, "Content-Type: text/html"))
  327.                 goto fetch_file_process_error_aborted;
  328.  
  329.         snprintf(key, sizeof key, "HTTP%03d", code);
  330.         title = messages_get(key);
  331.  
  332.         snprintf(buffer, sizeof buffer, "<html><head><title>%s</title></head>"
  333.                         "<body><h1>%s</h1>"
  334.                         "<p>Error %d while fetching file %s</p></body></html>",
  335.                         title, title, code, nsurl_access(ctx->url));
  336.  
  337.         msg.type = FETCH_DATA;
  338.         msg.data.header_or_data.buf = (const uint8_t *) buffer;
  339.         msg.data.header_or_data.len = strlen(buffer);
  340.         if (fetch_curl_send_callback(&msg, ctx))
  341.                 goto fetch_file_process_error_aborted;
  342.  
  343.         msg.type = FETCH_FINISHED;
  344.         fetch_curl_send_callback(&msg, ctx);
  345.  
  346. fetch_file_process_error_aborted:
  347.         return;
  348. }
  349.  
  350.  
  351. int is_pid(int k)
  352. {
  353.         int error;
  354. asm volatile ("int $0x40":"=a"(error):"a"(18), "b"(21), "c"(k));
  355. return error;
  356. }
  357.  
  358.  
  359. int kill_pid(int k)
  360. {
  361.         int error;
  362. asm volatile ("int $0x40":"=a"(error):"a"(18), "b"(18), "c"(k));
  363. return error;
  364. }
  365.  
  366. static void fetch_curl_process(struct fetch_curl_context *ctx) {
  367.        
  368.         int pid=execl ("/sys/network/downloader", ctx->path, 0);
  369.        
  370.        
  371.        
  372. //      while (is_pid(pid)) {
  373.         kill_pid(pid);
  374. //      }
  375.        
  376.         pid=execl ("/sys/network/downloader", ctx->path, 0);
  377.        
  378.         char ps[255];
  379.         sprintf(ps, "pid %d", pid);
  380.         execl ("/sys/network/@notify", ps, 0);
  381.        
  382.        
  383.         while (is_pid(pid));
  384.        
  385.        
  386.         sprintf(ps, "Yay! Finished");
  387.         execl ("/sys/network/@notify", ps, 0);
  388.        
  389.        
  390.         /*
  391.         char pzz[255];
  392.         sprintf(pzz, "Pid is %d", pid);
  393.         execl ("/sys/@notify", pzz, 0); */
  394.         //int status;
  395.         //waitpid(pid, &status, 0);
  396.        
  397.        
  398.         fetch_msg msg;
  399.         //const char * buf = "<html><body><h1>Hello, file fetcher!</h1></body></html>";
  400.  
  401.  FILE *infile;
  402.   infile = fopen("/sys/.download", "rb");
  403.  
  404.   if (infile == NULL) {
  405.     printf("file does not exist.\n");
  406.     return -1;
  407.   }
  408.  
  409.   fseek(infile, 0, SEEK_END);
  410.   size_t file_size = ftell(infile);
  411.   rewind(infile);
  412.  
  413.   char *buffer = (char*)malloc(file_size * sizeof(char));
  414.   if (buffer == NULL) {
  415.     fclose(infile);
  416.     printf("Error allocating %d bytes.\n", file_size * sizeof(char));
  417.     return -1;
  418.   }
  419.   size_t bytes_read = fread(buffer, sizeof(char), file_size, infile);
  420.   if (bytes_read != file_size) {
  421.     printf("Have read only %d bytes of %d.\n", bytes_read, file_size);
  422.     free(buffer);
  423.     fclose(infile);
  424.     return -1;
  425.   }
  426.   fclose(infile);
  427.  
  428.  
  429.        
  430.  
  431. /* fetch is going to be successful */
  432.         fetch_set_http_code(ctx->fetchh, 200);
  433.  
  434.         /* Any callback can result in the fetch being aborted.
  435.          * Therefore, we _must_ check for this after _every_ call to
  436.          * fetch_file_send_callback().
  437.          */
  438.  
  439.         __menuet__debug_out(fetch_filetype(ctx->path));
  440.         __menuet__debug_out("\n");
  441.        
  442.         if (fetch_curl_send_header(ctx, "Content-Type: %s",
  443.                         fetch_filetype(ctx->path)))
  444.                 goto fetch_file_process_aborted;
  445.  
  446.        
  447.         /* main data loop */
  448.  
  449.                 msg.type = FETCH_DATA;
  450.                 msg.data.header_or_data.buf = (const uint8_t *) buffer;
  451.                 msg.data.header_or_data.len = file_size;
  452.                 fetch_curl_send_callback(&msg, ctx);
  453.                        
  454.        
  455.  
  456.         if (ctx->aborted == false) {
  457.                 msg.type = FETCH_FINISHED;
  458.                 fetch_curl_send_callback(&msg, ctx);
  459.         }
  460.  
  461. fetch_file_process_aborted:
  462. return;
  463.  
  464. }
  465.  
  466.  
  467. /**
  468.  * Do some work on current fetches.
  469.  *
  470.  * Must be called regularly to make progress on fetches.
  471.  */
  472.  
  473. void fetch_curl_poll(lwc_string *scheme_ignored)
  474. {
  475.         LOG(("curl poll\n"));
  476.        
  477.         struct fetch_curl_context *c, *next;
  478.  
  479.         if (ring == NULL) return;
  480.  
  481.         /* Iterate over ring, processing each pending fetch */
  482.         c = ring;
  483.         do {
  484.                 /* Ignore fetches that have been flagged as locked.
  485.                  * This allows safe re-entrant calls to this function.
  486.                  * Re-entrancy can occur if, as a result of a callback,
  487.                  * the interested party causes fetch_poll() to be called
  488.                  * again.
  489.                  */
  490.                 if (c->locked == true) {
  491.                         next = c->r_next;
  492.                         continue;
  493.                 }
  494.  
  495.                 /* Only process non-aborted fetches */
  496.                 if (c->aborted == false) {
  497.                         /* file fetches can be processed in one go */
  498.                         fetch_curl_process(c);
  499.                 }
  500.  
  501.                 /* Compute next fetch item at the last possible moment as
  502.                  * processing this item may have added to the ring.
  503.                  */
  504.                 next = c->r_next;
  505.  
  506.                 fetch_remove_from_queues(c->fetchh);
  507.                 fetch_free(c->fetchh);
  508.  
  509.                 /* Advance to next ring entry, exiting if we've reached
  510.                  * the start of the ring or the ring has become empty
  511.                  */
  512.         } while ( (c = next) != ring && ring != NULL);
  513.  
  514. }
  515.  
  516.  
  517.  
  518.  
  519.