Beispiel #1
0
/*
 * Add a client to ClientQueue.
 *  - Every client-field is just a reference (except 'Web').
 *  - Return a unique number for identifying the client.
 */
static int Cache_client_enqueue(const DilloUrl *Url, DilloWeb *Web,
                                 CA_Callback_t Callback, void *CbData)
{
   static int ClientKey = 0; /* Provide a primary key for each client */
   CacheClient_t *NewClient;

   if (ClientKey < INT_MAX) /* check for integer overflow */
      ClientKey++;
   else
      ClientKey = 1;

   NewClient = dNew(CacheClient_t, 1);
   NewClient->Key = ClientKey;
   NewClient->Url = Url;
   NewClient->Version = 0;
   NewClient->Buf = NULL;
   NewClient->BufSize = 0;
   NewClient->Callback = Callback;
   NewClient->CbData = CbData;
   NewClient->Web    = Web;

   dList_append(ClientQueue, NewClient);

   return ClientKey;
}
Beispiel #2
0
/*
 * Create a new bitvec with 'num_bits' size
 */
bitvec_t *a_Bitvec_new(int num_bits)
{
   bitvec_t *bvec = dNew(bitvec_t, 1);

   bvec->vec = dNew0(uchar_t, num_bits/BVEC_SIZE + 1);
   bvec->len = num_bits;
   return bvec;
}
Beispiel #3
0
static AuthParse_t *Auth_parse_new()
{
   AuthParse_t *auth_parse = dNew(AuthParse_t, 1);
   auth_parse->ok = 0;
   auth_parse->type = TYPENOTSET;
   auth_parse->realm = NULL;
   auth_parse->nonce = NULL;
   auth_parse->opaque = NULL;
   auth_parse->stale = 0;
   auth_parse->algorithm = ALGORITHMNOTSET;
   auth_parse->domain = NULL;
   auth_parse->qop = QOPNOTSET;
   return auth_parse;
}
Beispiel #4
0
static void Http_socket_enqueue(SocketQueue_t *sq, SocketData_t* sock)
{
   SocketQueueEntry_t *se = dNew(SocketQueueEntry_t, 1);

   se->sock = sock;
   se->next = NULL;

   if (sq->tail)
      sq->tail->next = se;
   sq->tail = se;

   if (! sq->head)
      sq->head = se;
}
Beispiel #5
0
/*
 * Allocate and set a new entry in the cache list
 */
static CacheEntry_t *Cache_entry_add(const DilloUrl *Url)
{
   CacheEntry_t *old_entry, *new_entry;

   if ((old_entry = Cache_entry_search(Url))) {
      MSG_WARN("Cache_entry_add, leaking an entry.\n");
      dList_remove(CachedURLs, old_entry);
   }

   new_entry = dNew(CacheEntry_t, 1);
   Cache_entry_init(new_entry, Url);  /* Set safe values */
   dList_insert_sorted(CachedURLs, new_entry, Cache_entry_cmp);
   return new_entry;
}
Beispiel #6
0
/*
 * Create a new connection data structure
 */
static capi_conn_t *
 Capi_conn_new(DilloUrl *url, void *bw, char *server, char *datastr)
{
   capi_conn_t *conn;

   conn = dNew(capi_conn_t, 1);
   conn->url = url ? a_Url_dup(url) : NULL;
   conn->bw = bw;
   conn->server = dStrdup(server);
   conn->datastr = dStrdup(datastr);
   conn->SockFD = -1;
   conn->Flags = (strcmp(server, "http") != 0) ? PENDING : 0;
   conn->InfoSend = NULL;
   conn->InfoRecv = NULL;
   conn->Ref = 0;           /* Reference count */
   return conn;
}
Beispiel #7
0
/*
 * Create and initialize a dpip socket handler
 */
Dsh *a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz)
{
   Dsh *dsh = dNew(Dsh, 1);

   /* init descriptors and streams */
   dsh->fd_in  = fd_in;
   dsh->fd_out = fd_out;

   /* init buffer */
   dsh->wrbuf = dStr_sized_new(8 *1024);
   dsh->rdbuf = dStr_sized_new(8 *1024);
   dsh->flush_sz = flush_sz;
   dsh->mode = DPIP_TAG;
   if (fcntl(dsh->fd_in, F_GETFL) & O_NONBLOCK)
      dsh->mode |= DPIP_NONBLOCK;
   dsh->status = 0;

   return dsh;
}
Beispiel #8
0
/*
 * Set a timeout function to ask for user/password.
 */
static void Cache_auth_entry(CacheEntry_t *entry, BrowserWindow *bw)
{
   static int busy = 0;
   CacheAuthData_t *data;

   if (!entry) {
      busy = 0;
   } else if (busy) {
      MSG_WARN("Cache_auth_entry: caught busy!\n");
   } else if (entry->Auth) {
      busy = 1;
      data = dNew(CacheAuthData_t, 1);
      data->auth = entry->Auth;
      data->url = a_Url_dup(entry->Url);
      data->bw = bw;
      entry->Auth = NULL;
      a_Timeout_add(0.0, Cache_auth_callback, data);
   }
}
Beispiel #9
0
/*
 * Return: Nonzero if we got new credentials from the user and everything
 * seems fine.
 */
static int Auth_do_auth_dialog(const AuthParse_t *auth_parse,
                               const DilloUrl *url)
{
   int ret;
   char *title, *msg;
   AuthDialogData_t *data;
   const char *typestr = auth_parse->type == DIGEST ? "Digest" : "Basic";

   _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", auth_parse->realm);

   title = dStrconcat("Dillo: Password for ", auth_parse->realm, NULL);
   msg = dStrconcat("The server at ", URL_HOST(url), " requires a username"
                    " and password for  \"", auth_parse->realm, "\".\n\n"
                    "Authentication scheme: ", typestr, NULL);
   data = dNew(AuthDialogData_t, 1);
   data->auth_parse = auth_parse;
   data->url = a_Url_dup(url);
   ret = a_Dialog_user_password(title, msg, Auth_do_auth_dialog_cb, data);
   dFree(title); dFree(msg);
   a_Url_free((void *)data->url);
   dFree(data);
   return ret;
}
Beispiel #10
0
static void Auth_do_auth_dialog_cb(const char *user, const char *password,
                                   void *vData)
{
   AuthDialogData_t *data;
   AuthHost_t *host;
   AuthRealm_t *realm;

   data = (AuthDialogData_t *)vData;

   /* find or create the host */
   if (!(host = Auth_host_by_url(data->url))) {
      /* create a new host */
      host = dNew(AuthHost_t, 1);
      host->scheme = dStrdup(URL_SCHEME(data->url));
      host->authority = dStrdup(URL_AUTHORITY(data->url));
      host->realms = dList_new(1);
      dList_append(auth_hosts, host);
   }

   /* find or create the realm */
   if (!(realm = Auth_realm_by_name(host, data->auth_parse->realm))) {
      realm = dNew0(AuthRealm_t, 1);
      realm->name = dStrdup(data->auth_parse->realm);
      realm->paths = dList_new(1);
      dList_append(host->realms, realm);
   }
   realm->type = data->auth_parse->type;
   dFree(realm->authorization);
   realm->authorization = NULL;

   Auth_realm_add_path(realm, URL_PATH(data->url));

   if (realm->type == BASIC) {
      char *user_password = dStrconcat(user, ":", password, NULL);
      char *response = a_Misc_encode_base64(user_password);
      char *authorization =
         dStrconcat("Authorization: Basic ", response, "\r\n", NULL);
      dFree(realm->authorization);
      realm->authorization = authorization;
      dFree(response);
      dStrshred(user_password);
      dFree(user_password);
   } else if (realm->type == DIGEST) {
      dFree(realm->username);
      realm->username = dStrdup(user);
      realm->nonce_count = 0;
      dFree(realm->nonce);
      realm->nonce = dStrdup(data->auth_parse->nonce);
      dFree(realm->opaque);
      realm->opaque = dStrdup(data->auth_parse->opaque);
      realm->algorithm = data->auth_parse->algorithm;
      dFree(realm->domain);
      realm->domain = dStrdup(data->auth_parse->domain);
      realm->qop = data->auth_parse->qop;
      dFree(realm->cnonce);
      if (realm->qop != QOPNOTSET)
         realm->cnonce = a_Digest_create_cnonce();
      if (!a_Digest_compute_digest(realm, user, password)) {
         MSG("Auth_do_auth_dialog_cb: a_Digest_compute_digest failed.\n");
         dList_remove_fast(host->realms, realm);
         Auth_realm_delete(realm);
      }
   } else {
      MSG("Auth_do_auth_dialog_cb: Unknown auth type: %i\n",
          realm->type);
   }
   dStrshred((char *)password);
}
Beispiel #11
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;
}