Subversion Repositories Kolibri OS

Rev

Rev 4364 | Go to most recent revision | Blame | Last modification | View Log | 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.         __menuet__debug_out("Inside curl_send_cb, Calling send_cb()\n");
  291.  
  292.         fetch_send_callback(msg, ctx->fetchh);
  293.         ctx->locked = false;
  294.         __menuet__debug_out("Returning ctx->aborted.\n");
  295.  
  296.         return ctx->aborted;
  297. }
  298.  
  299. static bool fetch_curl_send_header(struct fetch_curl_context *ctx,
  300.                 const char *fmt, ...)
  301. {
  302.         fetch_msg msg;
  303.         char header[64];
  304.         va_list ap;
  305.         __menuet__debug_out("Inside fetch_curl_send_header\n");
  306.         va_start(ap, fmt);
  307.  
  308.         vsnprintf(header, sizeof header, fmt, ap);
  309.  
  310.         va_end(ap);
  311.         __menuet__debug_out("Header is : ");
  312.         __menuet__debug_out(header);
  313.  
  314.         msg.type = FETCH_HEADER;
  315.         msg.data.header_or_data.buf = (const uint8_t *) header;
  316.         msg.data.header_or_data.len = strlen(header);
  317.         __menuet__debug_out("\nCalling fetch_curl_send_callback\n");
  318.  
  319.         fetch_curl_send_callback(&msg, ctx);
  320.  
  321.         __menuet__debug_out("Returning ctx->aborted\n");
  322.         return ctx->aborted;
  323. }
  324.  
  325. static void fetch_curl_process_error(struct fetch_curl_context *ctx, int code)
  326. {
  327.         fetch_msg msg;
  328.         char buffer[1024];
  329.         const char *title;
  330.         char key[8];
  331.  
  332.         /* content is going to return error code */
  333.         fetch_set_http_code(ctx->fetchh, code);
  334.  
  335.         /* content type */
  336.         if (fetch_curl_send_header(ctx, "Content-Type: text/html"))
  337.                 goto fetch_file_process_error_aborted;
  338.  
  339.         snprintf(key, sizeof key, "HTTP%03d", code);
  340.         title = messages_get(key);
  341.  
  342.         snprintf(buffer, sizeof buffer, "<html><head><title>%s</title></head>"
  343.                         "<body><h1>%s</h1>"
  344.                         "<p>Error %d while fetching file %s</p></body></html>",
  345.                         title, title, code, nsurl_access(ctx->url));
  346.  
  347.         msg.type = FETCH_DATA;
  348.         msg.data.header_or_data.buf = (const uint8_t *) buffer;
  349.         msg.data.header_or_data.len = strlen(buffer);
  350.         if (fetch_curl_send_callback(&msg, ctx))
  351.                 goto fetch_file_process_error_aborted;
  352.  
  353.         msg.type = FETCH_FINISHED;
  354.         fetch_curl_send_callback(&msg, ctx);
  355.  
  356. fetch_file_process_error_aborted:
  357.         return;
  358. }
  359.  
  360.  
  361. static void fetch_curl_process(struct fetch_curl_context *ctx) {
  362.         char ps[96], str[128];
  363.         sprintf(ps, "Yay! Path is %s", ctx->path);
  364.         execl ("/sys/@notify", ps, 0);
  365.        
  366.         fetch_msg msg;
  367.  
  368.     __menuet__debug_out("AHOY!\n");
  369.         struct http_msg *http_ahoy;
  370.  
  371.         unsigned int wererat = 0;
  372.     char * pa=ctx->path;
  373.     //    asm volatile ("pusha");               // TODO: verify if this is still needed. It used to be an issue with the library but should be fixed now.
  374.     wererat = http_get(pa, NULL);       // TODO: a pointer to additional headers (for cookies etc) can be placed here in the future.
  375.     //    asm volatile ("popa");                // ....
  376.  
  377.     if(wererat == 0) /* Error condition : http_get returned 0 */
  378.       __menuet__debug_out("http_get() failed. [ Return Value 0 ]\n");    
  379.     else
  380.       __menuet__debug_out("http_get() Succeeded!. [ Return Value Non zero ]\n");      
  381.    
  382.     __menuet__debug_out("HTTP GOT!\n");
  383.     int result = 1337;
  384.     char result_str[12];
  385.     char wererat_str[13];
  386.  
  387.     http_ahoy = wererat;
  388.  
  389.     sprintf (str, "Header %u bytes, content %u bytes, received %u bytes\n", http_ahoy->header_length, http_ahoy->content_length, http_ahoy->content_received);
  390.     __menuet__debug_out(str);
  391.  
  392.     __menuet__debug_out("Going into the do while loop for http_process\n");
  393.  
  394.     do  {
  395.       //          sprintf(result_str, "%d", result);
  396.       //          __menuet__debug_out("Result is : ");
  397.       //          __menuet__debug_out(result_str);
  398.       //          __menuet__debug_out("\n");                
  399.    
  400.                 //              asm volatile ("pusha"); // TODO: verify if this is still needed. It used to be an issue with the library but should be fixed now.
  401.                 result = http_process(wererat);        
  402.                 //              asm volatile ("popa");  // ....
  403.     } while ((result != 0));
  404.  
  405.     __menuet__debug_out("After the do while loop for http_process.\n");
  406.    
  407.     if(result == 0)
  408.       __menuet__debug_out("http_process() worked successfully!\n");
  409.     else
  410.       __menuet__debug_out("http_process() failed!\n");
  411.  
  412. //    http_ahoy = wererat;              // really needed again??
  413.       sprintf (str, "Header %u bytes, content %u bytes, received %u bytes\n", http_ahoy->header_length, http_ahoy->content_length, http_ahoy->content_received);
  414.     __menuet__debug_out(str);
  415.  
  416. /* fetch is going to be successful */
  417.         __menuet__debug_out("Calling fetch_set_http_code call\n");
  418.         fetch_set_http_code(ctx->fetchh, http_ahoy->status);           
  419.         __menuet__debug_out("Returned from fetch_set_http_code call\n");
  420.  
  421.         /* Any callback can result in the fetch being aborted.
  422.          * Therefore, we _must_ check for this after _every_ call to
  423.          * fetch_file_send_callback().
  424.          */
  425.  
  426.         __menuet__debug_out("Calling fetch_curl_send_header: 1\n");    
  427.         if (fetch_curl_send_header(ctx, "Content-Type: %s",
  428.                         fetch_filetype(ctx->path)))
  429.                 goto fetch_file_process_aborted;
  430.  
  431.        
  432.         /* main data loop */
  433.         __menuet__debug_out("inside main data loop\n");
  434.                 msg.type = FETCH_DATA;
  435.  
  436.                 msg.data.header_or_data.buf = http_ahoy->content_ptr;   // lets pray this works..x2
  437.  
  438.                 msg.data.header_or_data.len = http_ahoy->content_received;
  439.         __menuet__debug_out("Calling fetch_curl_send_callback\n");
  440.                 fetch_curl_send_callback(&msg, ctx);
  441.  
  442.         __menuet__debug_out("Calling http_free with wererat = ");
  443.         sprintf(wererat_str, "%u", wererat);
  444.         __menuet__debug_out(wererat_str);
  445.         __menuet__debug_out("\n");
  446.                        
  447.         http_free(wererat);                    
  448.  
  449.         if (ctx->aborted == false) {
  450.         __menuet__debug_out("ctx->aborted = false\n");
  451.                 msg.type = FETCH_FINISHED;
  452.         __menuet__debug_out("Calling fetch_curl_send_callback\n");
  453.                 fetch_curl_send_callback(&msg, ctx);
  454.         __menuet__debug_out("After Calling fetch_curl_send_callback\n");
  455.         }
  456.  
  457. fetch_file_process_aborted:
  458.         __menuet__debug_out("Inside fetch file_process_aborted label\n");
  459. return;
  460.  
  461. }
  462.  
  463. /**
  464.  * Do some work on current fetches.
  465.  *
  466.  * Must be called regularly to make progress on fetches.
  467.  */
  468.  
  469. void fetch_curl_poll(lwc_string *scheme_ignored)
  470. {
  471.         LOG(("curl poll\n"));
  472.        
  473.         struct fetch_curl_context *c, *next;
  474.  
  475.         if (ring == NULL) return;
  476.  
  477.         /* Iterate over ring, processing each pending fetch */
  478.         c = ring;
  479.         do {
  480.                 /* Ignore fetches that have been flagged as locked.
  481.                  * This allows safe re-entrant calls to this function.
  482.                  * Re-entrancy can occur if, as a result of a callback,
  483.                  * the interested party causes fetch_poll() to be called
  484.                  * again.
  485.                  */
  486.                 if (c->locked == true) {
  487.                         next = c->r_next;
  488.                         continue;
  489.                 }
  490.  
  491.                 /* Only process non-aborted fetches */
  492.                 if (c->aborted == false) {
  493.                         /* file fetches can be processed in one go */
  494.                         fetch_curl_process(c);
  495.                 }
  496.  
  497.                 /* Compute next fetch item at the last possible moment as
  498.                  * processing this item may have added to the ring.
  499.                  */
  500.                 next = c->r_next;
  501.  
  502.                 fetch_remove_from_queues(c->fetchh);
  503.                 fetch_free(c->fetchh);
  504.  
  505.                 /* Advance to next ring entry, exiting if we've reached
  506.                  * the start of the ring or the ring has become empty
  507.                  */
  508.         } while ( (c = next) != ring && ring != NULL);
  509.  
  510. }
  511.  
  512.  
  513.  
  514.  
  515.