Subversion Repositories Kolibri OS

Rev

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