Beispiel #1
0
/*
 * Remove an entry, from the cache.
 * All the entry clients are removed too! (it may stop rendering of this
 * same resource on other windows, but nothing more).
 */
static void Cache_entry_remove(CacheEntry_t *entry, DilloUrl *url)
{
   int i;
   CacheClient_t *Client;

   if (!entry && !(entry = Cache_entry_search(url)))
      return;
   if (entry->Flags & CA_InternalUrl)
      return;

   /* remove all clients for this entry */
   for (i = 0; (Client = dList_nth_data(ClientQueue, i)); ++i) {
      if (Client->Url == entry->Url) {
         a_Cache_stop_client(Client->Key);
         --i;
      }
   }

   /* remove from DelayedQueue */
   dList_remove(DelayedQueue, entry);

   /* remove from dicache */
   a_Dicache_invalidate_entry(entry->Url);

   /* remove from cache */
   dList_remove(CachedURLs, entry);
   Cache_entry_free(entry);
}
Beispiel #2
0
/*
 * Given authentication challenge(s), prepare authorization.
 * Return: 0 on failure
 *         nonzero on success. A new query will be sent to the server.
 */
int a_Auth_do_auth(Dlist *challenges, const DilloUrl *url)
{
   int i;
   char *chal;

   for (i = 0; (chal = dList_nth_data(challenges, i)); ++i)
      if (!dStrnAsciiCasecmp(chal, "Digest ", 7))
         if (Auth_do_auth(chal, DIGEST, url))
            return 1;
   for (i = 0; (chal = dList_nth_data(challenges, i)); ++i)
      if (!dStrnAsciiCasecmp(chal, "Basic ", 6))
         if (Auth_do_auth(chal, BASIC, url))
            return 1;

   return 0;
}
Beispiel #3
0
/*
 *  Free Authentication fields.
 */
static void Cache_auth_free(Dlist *auth)
{
   int i;
   void *auth_field;
   for (i = 0; (auth_field = dList_nth_data(auth, i)); ++i)
      dFree(auth_field);
   dList_free(auth);
}
Beispiel #4
0
/*
 * Memory deallocator (only called at exit time)
 */
void a_Cache_freeall(void)
{
   CacheClient_t *Client;
   void *data;

   /* free the client queue */
   while ((Client = dList_nth_data(ClientQueue, 0)))
      Cache_client_dequeue(Client, NULLKey);

   /* Remove every cache entry */
   while ((data = dList_nth_data(CachedURLs, 0))) {
      dList_remove_fast(CachedURLs, data);
      Cache_entry_free(data);
   }
   /* Remove the cache list */
   dList_free(CachedURLs);
}
Beispiel #5
0
/*! Free memory used by the services list
 */
void free_services_list(Dlist *s_list)
{
   int i = 0;
   struct service *s;

   for (i=0; i < dList_length(s_list) ; i++) {
      s = dList_nth_data(s_list, i);
      dFree(s->name);
   }
   dList_free(s_list);
}
Beispiel #6
0
static int Auth_realm_includes_path(const AuthRealm_t *realm, const char *path)
{
   int i;
   char *realm_path;

   for (i = 0; (realm_path = dList_nth_data(realm->paths, i)); i++)
      if (Auth_path_is_inside(path, realm_path, strlen(realm_path)))
         return 1;

   return 0;
}
Beispiel #7
0
static void Http_host_connection_remove_all()
{
   HostConnection_t *hc;

   while (dList_length(host_connections) > 0) {
      hc = (HostConnection_t*) dList_nth_data(host_connections, 0);
      while (Http_socket_dequeue(&hc->queue));
      Http_host_connection_remove(hc);
   }
   dList_free(host_connections);
}
Beispiel #8
0
/*
 * Search all realms for the one with the given name.
 */
static AuthRealm_t *Auth_realm_by_name(const AuthHost_t *host,
                                           const char *name)
{
   AuthRealm_t *realm;
   int i;

   for (i = 0; (realm = dList_nth_data(host->realms, i)); i++)
      if (strcmp(realm->name, name) == 0)
         return realm;

   return NULL;
}
Beispiel #9
0
/*
 * Return the host that contains a URL, or NULL if there is no such host.
 */
static AuthHost_t *Auth_host_by_url(const DilloUrl *url)
{
   AuthHost_t *host;
   int i;

   for (i = 0; (host = dList_nth_data(auth_hosts, i)); i++)
      if (((dStrAsciiCasecmp(URL_SCHEME(url), host->scheme) == 0) &&
           (dStrAsciiCasecmp(URL_AUTHORITY(url), host->authority) == 0)))
         return host;

   return NULL;
}
Beispiel #10
0
/*
 * Search all realms for the one with the best-matching path.
 */
static AuthRealm_t *Auth_realm_by_path(const AuthHost_t *host,
                                       const char *path)
{
   AuthRealm_t *realm_best, *realm;
   int i, j;
   int match_length = 0;

   realm_best = NULL;
   for (i = 0; (realm = dList_nth_data(host->realms, i)); i++) {
      char *realm_path;

      for (j = 0; (realm_path = dList_nth_data(realm->paths, j)); j++) {
         int realm_path_length = strlen(realm_path);
         if (Auth_path_is_inside(path, realm_path, realm_path_length) &&
             !(realm_best && match_length >= realm_path_length)) {
            realm_best = realm;
            match_length = realm_path_length;
         }
      }
   }

   return realm_best;
}
Beispiel #11
0
/*
 * Callback function for Cache_delayed_process_queue.
 */
static void Cache_delayed_process_queue_callback()
{
   CacheEntry_t *entry;

   while ((entry = (CacheEntry_t *)dList_nth_data(DelayedQueue, 0))) {
      Cache_ref_data(entry);
      if ((entry = Cache_process_queue(entry))) {
         Cache_unref_data(entry);
         dList_remove(DelayedQueue, entry);
      }
   }
   DelayedQueueIdleId = 0;
   a_Timeout_remove();
}
Beispiel #12
0
/*
 * Last Client for this entry?
 * Return: Client if true, NULL otherwise
 * (cache.c has only one call to a capi function. This avoids a second one)
 */
CacheClient_t *a_Cache_client_get_if_unique(int Key)
{
   int i, n = 0;
   CacheClient_t *Client, *iClient;

   if ((Client = dList_find_custom(ClientQueue, INT2VOIDP(Key),
                                   Cache_client_by_key_cmp))) {
      for (i = 0; (iClient = dList_nth_data(ClientQueue, i)); ++i) {
         if (iClient->Url == Client->Url) {
            ++n;
         }
      }
   }
   return (n == 1) ? Client : NULL;
}
Beispiel #13
0
static void Auth_realm_delete(AuthRealm_t *realm)
{
   int i;

   MSG("Auth_realm_delete: \"%s\"\n", realm->name);
   for (i = dList_length(realm->paths) - 1; i >= 0; i--)
      dFree(dList_nth_data(realm->paths, i));
   dList_free(realm->paths);
   dFree(realm->name);
   dFree(realm->username);
   dFree(realm->authorization);
   dFree(realm->cnonce);
   dFree(realm->nonce);
   dFree(realm->opaque);
   dFree(realm->domain);
   dFree(realm);
}
Beispiel #14
0
/*
 * Resume connections that were waiting for dpid to start.
 */
static void Capi_conn_resume(void)
{
   int i;
   DataBuf *dbuf;
   capi_conn_t *conn;

   for (i = 0; i < dList_length(CapiConns); ++i) {
      conn = dList_nth_data (CapiConns, i);
      if (conn->Flags & PENDING) {
         dbuf = a_Chain_dbuf_new(conn->datastr,(int)strlen(conn->datastr), 0);
         if (conn->InfoSend) {
            a_Capi_ccc(OpSend, 1, BCK, conn->InfoSend, dbuf, NULL);
         }
         dFree(dbuf);
         conn->Flags &= ~PENDING;
      }
   }
}
Beispiel #15
0
/*
 * Abort the connection for a given url, using its CCC.
 * (OpAbort 2,BCK removes the cache entry)
 * TODO: when conn is already done, the cache entry isn't removed.
 *       This may be wrong and needs a revision. 
 */
void a_Capi_conn_abort_by_url(const DilloUrl *url)
{
   int i;
   capi_conn_t *conn;

   for (i = 0; i < dList_length(CapiConns); ++i) {
      conn = dList_nth_data (CapiConns, i);
      if (a_Url_cmp(conn->url, url) == 0) {
         if (conn->InfoSend) {
            a_Capi_ccc(OpAbort, 1, BCK, conn->InfoSend, NULL, NULL);
         }
         if (conn->InfoRecv) {
            a_Capi_ccc(OpAbort, 2, BCK, conn->InfoRecv, NULL, NULL);
         }
         break;
      }
   }
}
Beispiel #16
0
static HostConnection_t *Http_host_connection_get(const char *host)
{
   int i;
   HostConnection_t *hc;

   for (i = 0; i < dList_length(host_connections); i++) {
      hc = (HostConnection_t*) dList_nth_data(host_connections, i);

      if (dStrAsciiCasecmp(host, hc->host) == 0)
         return hc;
   }

   hc = dNew0(HostConnection_t, 1);
   Http_socket_queue_init(&hc->queue);
   hc->host = dStrdup(host);
   dList_append(host_connections, hc);

   return hc;
}
Beispiel #17
0
static void Auth_realm_add_path(AuthRealm_t *realm, const char *path)
{
   int len, i;
   char *realm_path, *n_path;

   n_path = dStrdup(path);
   len = strlen(n_path);

   /* remove trailing '/' */
   if (len && n_path[len - 1] == '/')
      n_path[--len] = 0;

   /* delete existing paths that are inside the new one */
   for (i = 0; (realm_path = dList_nth_data(realm->paths, i)); i++) {
      if (Auth_path_is_inside(realm_path, path, len)) {
         dList_remove_fast(realm->paths, realm_path);
         dFree(realm_path);
         i--; /* reconsider this slot */
      }
   }

   dList_append(realm->paths, n_path);
}
Beispiel #18
0
/*
 * Scan, allocate, and set things according to header info.
 * (This function needs the whole header to work)
 */
static void Cache_parse_header(CacheEntry_t *entry)
{
   char *header = entry->Header->str;
   char *Length, *Type, *location_str, *encoding;
#ifndef DISABLE_COOKIES
   Dlist *Cookies;
#endif
   Dlist *warnings;
   void *data;
   int i;

   _MSG("Cache_parse_header\n");

   if (entry->Header->len > 12) {
      if (header[9] == '1' && header[10] == '0' && header[11] == '0') {
         /* 100: Continue. The "real" header has not come yet. */
         MSG("An actual 100 Continue header!\n");
         entry->Flags &= ~CA_GotHeader;
         dStr_free(entry->Header, 1);
         entry->Header = dStr_new("");
         return;
      }
      if (header[9] == '3' && header[10] == '0' &&
          (location_str = Cache_parse_field(header, "Location"))) {
         /* 30x: URL redirection */
         DilloUrl *location_url = a_Url_new(location_str,URL_STR_(entry->Url));

         if (prefs.filter_auto_requests == PREFS_FILTER_SAME_DOMAIN &&
             !a_Url_same_organization(entry->Url, location_url)) {
            /* don't redirect; just show body like usual (if any) */
            MSG("Redirection not followed from %s to %s\n",
                URL_HOST(entry->Url), URL_STR(location_url));
            a_Url_free(location_url);
         } else {
            entry->Flags |= CA_Redirect;
            if (header[11] == '1')
               entry->Flags |= CA_ForceRedirect;  /* 301 Moved Permanently */
            else if (header[11] == '2')
               entry->Flags |= CA_TempRedirect;   /* 302 Temporary Redirect */

            if (URL_FLAGS(location_url) & (URL_Post + URL_Get) &&
                dStrAsciiCasecmp(URL_SCHEME(location_url), "dpi") == 0 &&
                dStrAsciiCasecmp(URL_SCHEME(entry->Url), "dpi") != 0) {
               /* Forbid dpi GET and POST from non dpi-generated urls */
               MSG("Redirection Denied! '%s' -> '%s'\n",
                   URL_STR(entry->Url), URL_STR(location_url));
               a_Url_free(location_url);
            } else {
               entry->Location = location_url;
            }
         }
         dFree(location_str);
      } else if (strncmp(header + 9, "401", 3) == 0) {
         entry->Auth =
            Cache_parse_multiple_fields(header, "WWW-Authenticate");
      } else if (strncmp(header + 9, "404", 3) == 0) {
         entry->Flags |= CA_NotFound;
      }
   }

   if ((warnings = Cache_parse_multiple_fields(header, "Warning"))) {
      for (i = 0; (data = dList_nth_data(warnings, i)); ++i) {
         MSG_HTTP("%s\n", (char *)data);
         dFree(data);
      }
      dList_free(warnings);
   }

   /*
    * Get Transfer-Encoding and initialize decoder
    */
   encoding = Cache_parse_field(header, "Transfer-Encoding");
   entry->TransferDecoder = a_Decode_transfer_init(encoding);


   if ((Length = Cache_parse_field(header, "Content-Length")) != NULL) {
      if (encoding) {
         /*
          * If Transfer-Encoding is present, Content-Length must be ignored.
          * If the Transfer-Encoding is non-identity, it is an error.
          */
         if (dStrAsciiCasecmp(encoding, "identity"))
            MSG_HTTP("Content-Length and non-identity Transfer-Encoding "
                     "headers both present.\n");
      } else {
         entry->Flags |= CA_GotLength;
         entry->ExpectedSize = MAX(strtol(Length, NULL, 10), 0);
      }
      dFree(Length);
   }

   dFree(encoding); /* free Transfer-Encoding */

#ifndef DISABLE_COOKIES
   if ((Cookies = Cache_parse_multiple_fields(header, "Set-Cookie"))) {
      CacheClient_t *client;

      for (i = 0; (client = dList_nth_data(ClientQueue, i)); ++i) {
         if (client->Url == entry->Url) {
            DilloWeb *web = client->Web;

            if (!web->requester ||
                a_Url_same_organization(entry->Url, web->requester)) {
               char *server_date = Cache_parse_field(header, "Date");

               a_Cookies_set(Cookies, entry->Url, server_date);
               dFree(server_date);
               break;
            }
         }
      }
      if (i >= dList_length(ClientQueue)) {
         MSG("Cache: cookies not accepted from '%s'\n", URL_STR(entry->Url));
      }

      for (i = 0; (data = dList_nth_data(Cookies, i)); ++i)
         dFree(data);
      dList_free(Cookies);
   }
#endif /* !DISABLE_COOKIES */

   /*
    * Get Content-Encoding and initialize decoder
    */
   encoding = Cache_parse_field(header, "Content-Encoding");
   entry->ContentDecoder = a_Decode_content_init(encoding);
   dFree(encoding);

   if (entry->ExpectedSize > 0) {
      if (entry->ExpectedSize > HUGE_FILESIZE) {
         entry->Flags |= CA_HugeFile;
      }
      /* Avoid some reallocs. With MAX_INIT_BUF we avoid a SEGFAULT
       * with huge files (e.g. iso files).
       * Note: the buffer grows automatically. */
      dStr_free(entry->Data, 1);
      entry->Data = dStr_sized_new(MIN(entry->ExpectedSize, MAX_INIT_BUF));
   }

   /* Get Content-Type */
   if ((Type = Cache_parse_field(header, "Content-Type"))) {
      /* This HTTP Content-Type is not trusted. It's checked against real data
       * in Cache_process_queue(); only then CA_GotContentType becomes true. */
      a_Cache_set_content_type(entry->Url, Type, "http");
      _MSG("TypeHdr  {%s} {%s}\n", Type, URL_STR(entry->Url));
      _MSG("TypeMeta {%s}\n", entry->TypeMeta);
      dFree(Type);
   }
   Cache_ref_data(entry);
}
Beispiel #19
0
/*
 * This function gets called after the DNS succeeds solving a hostname.
 * Task: Finish socket setup and start connecting the socket.
 * Return value: 0 on success;  -1 on error.
 */
static int Http_connect_socket(ChainLink *Info)
{
   int i, status;
#ifdef ENABLE_IPV6
   struct sockaddr_in6 name;
#else
   struct sockaddr_in name;
#endif
   SocketData_t *S;
   DilloHost *dh;
   socklen_t socket_len = 0;

   S = a_Klist_get_data(ValidSocks, VOIDP2INT(Info->LocalKey));

   /* TODO: iterate this address list until success, or end-of-list */
   for (i = 0; (dh = dList_nth_data(S->addr_list, i)); ++i) {
      if ((S->SockFD = socket(dh->af, SOCK_STREAM, IPPROTO_TCP)) < 0) {
         S->Err = errno;
         MSG("Http_connect_socket ERROR: %s\n", dStrerror(errno));
         continue;
      }
      /* set NONBLOCKING and close on exec. */
      fcntl(S->SockFD, F_SETFL, O_NONBLOCK | fcntl(S->SockFD, F_GETFL));
      fcntl(S->SockFD, F_SETFD, FD_CLOEXEC | fcntl(S->SockFD, F_GETFD));

      /* Some OSes require this...  */
      memset(&name, 0, sizeof(name));
      /* Set remaining parms. */
      switch (dh->af) {
      case AF_INET:
      {
         struct sockaddr_in *sin = (struct sockaddr_in *)&name;
         socket_len = sizeof(struct sockaddr_in);
         sin->sin_family = dh->af;
         sin->sin_port = S->port ? htons(S->port) : htons(DILLO_URL_HTTP_PORT);
         memcpy(&sin->sin_addr, dh->data, (size_t)dh->alen);
         if (a_Web_valid(S->web) && (S->web->flags & WEB_RootUrl))
            MSG("Connecting to %s\n", inet_ntoa(sin->sin_addr));
         break;
      }
#ifdef ENABLE_IPV6
      case AF_INET6:
      {
         char buf[128];
         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&name;
         socket_len = sizeof(struct sockaddr_in6);
         sin6->sin6_family = dh->af;
         sin6->sin6_port =
            S->port ? htons(S->port) : htons(DILLO_URL_HTTP_PORT);
         memcpy(&sin6->sin6_addr, dh->data, dh->alen);
         inet_ntop(dh->af, dh->data, buf, sizeof(buf));
         if (a_Web_valid(S->web) && (S->web->flags & WEB_RootUrl))
            MSG("Connecting to %s\n", buf);
         break;
      }
#endif
      }/*switch*/

      MSG_BW(S->web, 1, "Contacting host...");
      status = connect(S->SockFD, (struct sockaddr *)&name, socket_len);
      if (status == -1 && errno != EINPROGRESS) {
         S->Err = errno;
         Http_socket_close(S);
         MSG("Http_connect_socket ERROR: %s\n", dStrerror(S->Err));
      } else {
         a_Chain_bcb(OpSend, Info, &S->SockFD, "FD");
         a_Chain_fcb(OpSend, Info, &S->SockFD, "FD");
         Http_send_query(S->Info, S);
         return 0; /* Success */
      }
   }

   return -1;
}
Beispiel #20
0
/*
 * Update cache clients for a single cache-entry
 * Tasks:
 *   - Set the client function (if not already set)
 *   - Look if new data is available and pass it to client functions
 *   - Remove clients when done
 *   - Call redirect handler
 *
 * Return: Cache entry, which may be NULL if it has been removed.
 *
 * TODO: Implement CA_Abort Op in client callback
 */
static CacheEntry_t *Cache_process_queue(CacheEntry_t *entry)
{
   uint_t i;
   int st;
   const char *Type;
   Dstr *data;
   CacheClient_t *Client;
   DilloWeb *ClientWeb;
   BrowserWindow *Client_bw = NULL;
   static bool_t Busy = FALSE;
   bool_t AbortEntry = FALSE;
   bool_t OfferDownload = FALSE;
   bool_t TypeMismatch = FALSE;

   if (Busy)
      MSG_ERR("FATAL!: >>>> Cache_process_queue Caught busy!!! <<<<\n");
   if (!(entry->Flags & CA_GotHeader))
      return entry;
   if (!(entry->Flags & CA_GotContentType)) {
      st = a_Misc_get_content_type_from_data(
              entry->Data->str, entry->Data->len, &Type);
      _MSG("Cache: detected Content-Type '%s'\n", Type);
      if (st == 0 || entry->Flags & CA_GotData) {
         if (a_Misc_content_type_check(entry->TypeHdr, Type) < 0) {
            MSG_HTTP("Content-Type '%s' doesn't match the real data.\n",
                     entry->TypeHdr);
            TypeMismatch = TRUE;
         }
         entry->TypeDet = dStrdup(Type);
         entry->Flags |= CA_GotContentType;
      } else
         return entry;  /* i.e., wait for more data */
   }

   Busy = TRUE;
   for (i = 0; (Client = dList_nth_data(ClientQueue, i)); ++i) {
      if (Client->Url == entry->Url) {
         ClientWeb = Client->Web;    /* It was a (void*) */
         Client_bw = ClientWeb->bw;  /* 'bw' in a local var */

         if (ClientWeb->flags & WEB_RootUrl) {
            if (!(entry->Flags & CA_MsgErased)) {
               /* clear the "expecting for reply..." message */
               a_UIcmd_set_msg(Client_bw, "");
               entry->Flags |= CA_MsgErased;
            }
            if (TypeMismatch) {
               a_UIcmd_set_msg(Client_bw,"HTTP warning: Content-Type '%s' "
                               "doesn't match the real data.", entry->TypeHdr);
               OfferDownload = TRUE;
            }
            if (entry->Flags & CA_Redirect) {
               if (!Client->Callback) {
                  Client->Callback = Cache_null_client;
                  Client_bw->redirect_level++;
               }
            } else {
               Client_bw->redirect_level = 0;
            }
            if (entry->Flags & CA_HugeFile) {
               a_UIcmd_set_msg(Client_bw,"Huge file! (%dMB)",
                               entry->ExpectedSize / (1024*1024));
               AbortEntry = OfferDownload = TRUE;
            }
         } else {
            /* For non root URLs, ignore redirections and 404 answers */
            if (entry->Flags & CA_Redirect || entry->Flags & CA_NotFound)
               Client->Callback = Cache_null_client;
         }

         /* Set the client function */
         if (!Client->Callback) {
            Client->Callback = Cache_null_client;
            if (TypeMismatch) {
               AbortEntry = TRUE;
            } else {
               const char *curr_type = Cache_current_content_type(entry);
               st = a_Web_dispatch_by_type(curr_type, ClientWeb,
                                           &Client->Callback, &Client->CbData);
               if (st == -1) {
                  /* MIME type is not viewable */
                  if (ClientWeb->flags & WEB_RootUrl) {
                     MSG("Content-Type '%s' not viewable.\n", curr_type);
                     /* prepare a download offer... */
                     AbortEntry = OfferDownload = TRUE;
                  } else {
                     /* TODO: Resource Type not handled.
                      * Not aborted to avoid multiple connections on the same
                      * resource. A better idea is to abort the connection and
                      * to keep a failed-resource flag in the cache entry. */
                  }
               }
            }
            if (AbortEntry) {
               if (ClientWeb->flags & WEB_RootUrl)
                  a_Nav_cancel_expect_if_eq(Client_bw, Client->Url);
               a_Bw_remove_client(Client_bw, Client->Key);
               Cache_client_dequeue(Client, NULLKey);
               --i; /* Keep the index value in the next iteration */
               continue;
            }
         }

         /* Send data to our client */
         if (ClientWeb->flags & WEB_Download) {
            /* for download, always provide original data, not translated */
            data = entry->Data;
         } else {
            data = Cache_data(entry);
         }
         if ((Client->BufSize = data->len) > 0) {
            Client->Buf = data->str;
            (Client->Callback)(CA_Send, Client);
            if (ClientWeb->flags & WEB_RootUrl) {
               /* show size of page received */
               a_UIcmd_set_page_prog(Client_bw, entry->Data->len, 1);
            }
         }

         /* Remove client when done */
         if (entry->Flags & CA_GotData) {
            /* Copy flags to a local var */
            int flags = ClientWeb->flags;
            /* We finished sending data, let the client know */
            (Client->Callback)(CA_Close, Client);
            if (ClientWeb->flags & WEB_RootUrl)
               a_UIcmd_set_page_prog(Client_bw, 0, 0);
            Cache_client_dequeue(Client, NULLKey);
            --i; /* Keep the index value in the next iteration */

            /* within CA_GotData, we assert just one redirect call */
            if (entry->Flags & CA_Redirect)
               Cache_redirect(entry, flags, Client_bw);
         }
      }
   } /* for */

   if (AbortEntry) {
      /* Abort the entry, remove it from cache, and maybe offer download. */
      DilloUrl *url = a_Url_dup(entry->Url);
      a_Capi_conn_abort_by_url(url);
      entry = NULL;
      if (OfferDownload) {
         /* Remove entry when 'conn' is already done */
         Cache_entry_remove(NULL, url);
         if (a_Cache_download_enabled(url)) {
            Cache_savelink_t *data = dNew(Cache_savelink_t, 1);
            data->bw = Client_bw;
            data->url = a_Url_dup(url);
            a_Timeout_add(0.0, Cache_savelink_cb, data);
         }
      }
      a_Url_free(url);
   } else if (entry->Auth && (entry->Flags & CA_GotData)) {
      Cache_auth_entry(entry, Client_bw);
   }

   /* Trigger cleanup when there are no cache clients */
   if (dList_length(ClientQueue) == 0) {
      _MSG("  a_Dicache_cleanup()\n");
      a_Dicache_cleanup();
   }

   Busy = FALSE;
   _MSG("QueueSize ====> %d\n", dList_length(ClientQueue));
   return entry;
}
Beispiel #21
0
/*
 * Flush cookies to disk and free all the memory allocated.
 */
static void Cookies_save_and_free()
{
   int i, fd, saved = 0;
   DomainNode *node;
   CookieData_t *cookie;
   time_t now;

#ifndef HAVE_LOCKF
   struct flock lck;
#endif

   if (disabled)
      return;

   now = time(NULL);

   rewind(file_stream);
   fd = fileno(file_stream);
   if (ftruncate(fd, 0) == -1)
      MSG("Cookies: Truncate file stream failed: %s\n", dStrerror(errno));
   fprintf(file_stream, "%s", cookies_txt_header_str);

   /* Iterate cookies per domain, saving and freeing */
   while ((node = dList_nth_data(domains, 0))) {
      for (i = 0; (cookie = dList_nth_data(node->cookies, i)); ++i) {
         if (!cookie->session_only && difftime(cookie->expires_at, now) > 0) {
            int len;
            char buf[LINE_MAXLEN];

            len = snprintf(buf, LINE_MAXLEN, "%s\t%s\t%s\t%s\t%ld\t%s\t%s\n",
                           cookie->domain,
                           cookie->host_only ? "FALSE" : "TRUE",
                           cookie->path,
                           cookie->secure ? "TRUE" : "FALSE",
                           (long) difftime(cookie->expires_at,
                                           cookies_epoch_time),
                           cookie->name,
                           cookie->value);
            if (len < LINE_MAXLEN) {
               fprintf(file_stream, "%s", buf);
               saved++;
            } else {
               MSG("Not saving overly long cookie for %s.\n", cookie->domain);
            }
         }
         Cookies_free_cookie(cookie);
      }
      Cookies_delete_node(node);
   }
   dList_free(domains);
   dList_free(all_cookies);

#ifdef HAVE_LOCKF
   lockf(fd, F_ULOCK, 0);
#else  /* POSIX file lock */
   lck.l_start = 0; /* start at beginning of file */
   lck.l_len = 0;  /* lock entire file */
   lck.l_type = F_UNLCK;
   lck.l_whence = SEEK_SET;  /* absolute offset */

   fcntl(fileno(file_stream), F_SETLKW, &lck);
#endif
   fclose(file_stream);

   MSG("Cookies saved: %d.\n", saved);
}
Beispiel #22
0
/*
 * Receive new data, update the reception buffer (for next read), update the
 * cache, and service the client queue.
 *
 * This function gets called whenever the IO has new data.
 *  'Op' is the operation to perform
 *  'VPtr' is a (void) pointer to the IO control structure
 */
bool_t a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size,
                            const DilloUrl *Url)
{
   int offset, len;
   const char *str;
   Dstr *dstr1, *dstr2, *dstr3;
   bool_t done = FALSE;
   CacheEntry_t *entry = Cache_entry_search(Url);

   /* Assert a valid entry (not aborted) */
   dReturn_val_if_fail (entry != NULL, FALSE);

   _MSG("__a_Cache_process_dbuf__\n");

   if (Op == IORead) {
      /*
       * Cache_get_header() will set CA_GotHeader if it has a full header, and
       * Cache_parse_header() will unset it if the header ends being
       * merely an informational response from the server (i.e., 100 Continue)
       */
      for (offset = 0; !(entry->Flags & CA_GotHeader) &&
           (len = Cache_get_header(entry, buf + offset, buf_size - offset));
           Cache_parse_header(entry) ) {
         offset += len;
      }

      if (entry->Flags & CA_GotHeader) {
         str = buf + offset;
         len = buf_size - offset;
         entry->TransferSize += len;
         dstr1 = dstr2 = dstr3 = NULL;

         /* Decode arrived data (<= 3 stages) */
         if (entry->TransferDecoder) {
            dstr1 = a_Decode_transfer_process(entry->TransferDecoder, str,len);
            done = a_Decode_transfer_finished(entry->TransferDecoder);
            str = dstr1->str;
            len = dstr1->len;
         }
         if (entry->ContentDecoder) {
            dstr2 = a_Decode_process(entry->ContentDecoder, str, len);
            str = dstr2->str;
            len = dstr2->len;
         }
         dStr_append_l(entry->Data, str, len);
         if (entry->CharsetDecoder && entry->UTF8Data) {
            dstr3 = a_Decode_process(entry->CharsetDecoder, str, len);
            dStr_append_l(entry->UTF8Data, dstr3->str, dstr3->len);
         }
         dStr_free(dstr1, 1);
         dStr_free(dstr2, 1);
         dStr_free(dstr3, 1);

         if (entry->Data->len)
            entry->Flags &= ~CA_IsEmpty;

         if ((entry->Flags & CA_GotLength) &&
             (entry->TransferSize >= entry->ExpectedSize)) {
            done = TRUE;
         }
         if (!(entry->Flags & CA_KeepAlive)) {
            /* Let IOClose finish it later */
            done = FALSE;
         }

         entry = Cache_process_queue(entry);

         if (entry && done)
            Cache_finish_msg(entry);
      }
   } else if (Op == IOClose) {
      Cache_finish_msg(entry);
   } else if (Op == IOAbort) {
      int i;
      CacheClient_t *Client;

      for (i = 0; (Client = dList_nth_data(ClientQueue, i)); ++i) {
         if (Client->Url == entry->Url) {
            DilloWeb *web = (DilloWeb *)Client->Web;

            a_Bw_remove_client(web->bw, Client->Key);
            Cache_client_dequeue(Client);
            --i; /* Keep the index value in the next iteration */
         }
      }
   }
   return done;
}