⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 http-cache.c

📁 Serveez是一个服务器框架
💻 C
字号:
/* * http-cache.c - http protocol file cache * * Copyright (C) 2000, 2001 Stefan Jahn <stefan@lkcc.org> * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. *  * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. *  * You should have received a copy of the GNU General Public License * along with this package; see the file COPYING.  If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA.   * * $Id: http-cache.c,v 1.33 2001/09/12 13:42:15 ela Exp $ * */#if HAVE_CONFIG_H# include <config.h>#endif#if ENABLE_HTTP_PROTO#define _GNU_SOURCE#include <assert.h>#include <stdio.h>#include <string.h>#include <errno.h>#if HAVE_UNISTD_H# include <unistd.h>#endif#ifdef __MINGW32__# include <winsock2.h># include <io.h>#endif#ifndef __MINGW32__# include <sys/types.h># include <sys/socket.h>#endif#include "libserveez.h"#include "http-proto.h"#include "http-core.h"#include "http-cache.h"svz_hash_t *http_cache = NULL;               /* actual cache entry hash */int http_cache_entries = 0;                  /* amount of cache entries */http_cache_entry_t *http_cache_first = NULL; /* most recent entry */http_cache_entry_t *http_cache_last = NULL;  /* least recent entry *//* * This will initialize the http cache entries. */voidhttp_alloc_cache (int entries){  if (entries > http_cache_entries || http_cache == NULL)    {      if (http_cache)	http_free_cache ();      http_cache = svz_hash_create (entries);      http_cache_entries = entries;#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "cache: created %d cache entries\n", entries);#endif    }}/* * Free all the cache entries. */voidhttp_free_cache (void){  int total, files;  http_cache_entry_t *cache, *next;  files = total = 0;  for (cache = http_cache_first; cache; cache = next)    {      next = cache->next;      total += cache->size;      files++;      svz_free (cache->buffer);      svz_free (cache->file);      svz_free (cache);    }  svz_hash_destroy (http_cache);  http_cache_first = http_cache_last = NULL;  http_cache = NULL;#if ENABLE_DEBUG  svz_log (LOG_DEBUG, "cache: freeing %d byte in %d entries\n", total, files); #endif}#if ENABLE_DEBUG/* * Check consistency of the http cache. Remove this function once the  * server is stable. */static voidhttp_cache_consistency (void){  int n, o;  http_cache_entry_t **cache;  n = 1;  svz_hash_foreach_value (http_cache, cache, o)    {      /* each cache entry must have a file name */      assert (cache[o]->file);      /* cache entry must be completely unused if not ready */      if (!cache[o]->ready)	{	  assert (cache[o]->size == 0 &&		  cache[o]->buffer == NULL && cache[o]->hits == 0);	}      /* if ready a cache entry must contain something */      else	{	  assert (cache[o]->size >= 0 && 		  cache[o]->buffer && cache[o]->hits >= 0);	}    }}#else /* not ENABLE_DEBUG */# define http_cache_consistency()#endif /* not ENABLE_DEBUG */#if ENABLE_DEBUGstatic voidhttp_cache_print (void){  int n;  http_cache_entry_t *entry;  printf ("cache first: %p\n", (void *) http_cache_first);  for (n = 0, entry = http_cache_first; entry; entry = entry->next, n++)    {      printf ("cache entry: %p, prev: %p, next: %p\n",	      (void *) entry, (void *) entry->prev, (void *) entry->next);    }  printf ("cache last: %p\n", (void *) http_cache_last);}#else# define http_cache_print()#endif /* ENABLE_DEBUG *//* * Returns the urgency value of the given http cache entry CACHE. */inthttp_cache_urgency (http_cache_entry_t *cache){  int n;  http_cache_entry_t *entry;  for (n = 0, entry = http_cache_first; entry; entry = entry->next, n++)    if (entry == cache)      return n;  return -1;}/* * This function will make the given cache entry CACHE the most recent  * within the whole HTTP file cache. All other used entries will be less * urgent afterwards. */voidhttp_urgent_cache (http_cache_entry_t *cache){  if (cache->prev)    {      cache->prev->next = cache->next;      if (cache->next)	cache->next->prev = cache->prev;      else	http_cache_last = cache->prev;      http_cache_first->prev = cache;      cache->next = http_cache_first;      cache->prev = NULL;      http_cache_first = cache;    }}/* * This routine checks if a certain FILE is already within the HTTP file  * cache. It returns HTTP_CACHE_COMPLETE if it is already cached and fills  * in the CACHE entry. This entry will be additionally the most recent  * afterwards. If the given FILE is going to be in the cache then return  * HTTP_CACHE_INCOMPLETE, return HTTP_CACHE_NO if it is not at all in the  * cache. */inthttp_check_cache (char *file, http_cache_t *cache){  http_cache_entry_t *cachefile;  if ((cachefile = svz_hash_get (http_cache, file)) != NULL)    {      /* set this entry to the most recent, ready or not  */      http_urgent_cache (cachefile);      http_cache_consistency ();      /* is this entry fully read by the cache reader ? */      if (cachefile->ready)	{	  /* fill in the cache entry for the cache writer */	  cache->entry = cachefile;	  cache->buffer = cachefile->buffer;	  cache->size = cachefile->size;	  return HTTP_CACHE_COMPLETE;	}      /* not but is going to be ... */      return HTTP_CACHE_INCOMPLETE;    }  return HTTP_CACHE_NO;}/* * Create a new http cache entry and initialize it. */static http_cache_entry_t *http_cache_create_entry (void){  http_cache_entry_t *cache;  cache = svz_malloc (sizeof (http_cache_entry_t));  memset (cache, 0, sizeof (http_cache_entry_t));  return cache;}/* * Destroy an existing http cache entry and remove it from the cache hash.  */static voidhttp_cache_destroy_entry (http_cache_entry_t *cache){  http_cache_consistency ();  /* Delete cache entry from hash. */  if (svz_hash_delete (http_cache, cache->file) != cache)    svz_log (LOG_FATAL, "cache: inconsistent http hash\n");  /* Update the double chained list of entries. */  if (cache->prev)    cache->prev->next = cache->next;  else    http_cache_first = cache->next;  if (cache->next)    cache->next->prev = cache->prev;  else    http_cache_last = cache->prev;  if (cache->ready)    svz_free (cache->buffer);  svz_free (cache->file);  svz_free (cache);}/* * Reset the cache entry of a http sockets cache structure. */static voidhttp_cache_reset (http_cache_t *cache){  cache->size = 0;  cache->buffer = NULL;  cache->entry = NULL;}/* * This is a extended callback for the sock->disconnected_socket entry * of a socket structure. You should assign it if the socket reads a * cache entry. */inthttp_cache_disconnect (svz_socket_t *sock){  http_socket_t *http = sock->data;  if (http->cache && http->cache->entry)    {      /* if the cache entry has not been fully read then free it */      if (!http->cache->entry->ready)	{	  http_cache_destroy_entry (http->cache->entry);	  svz_free (http->cache->buffer);	  http_cache_reset (http->cache);	}    }  return http_disconnect (sock);}/* * Find a free slot in the http file cache entries. If necessary * delete the least recent. Return zero if there was a free slot. */inthttp_init_cache (char *file, http_cache_t *cache){  http_cache_entry_t *entry, *slot = NULL;  /*    * If there are still empty cache entries then create a    * new cache entry.   */  if (svz_hash_size (http_cache) < http_cache_entries)    {      slot = http_cache_create_entry ();    }  /*   * Otherwise find the least recent which is not currently in   * use by the cache writer or reader.   */  else    {      for (entry = http_cache_last; entry; entry = entry->prev)	if (!entry->usage && entry->ready)	  {	    slot = entry;	    break;	  }      /* not a "reinitialable" cache entry found */      if (!slot) 	{	  http_cache_reset (cache);	  http_cache_consistency ();	  return -1;	}      /* is currently used, so free the entry previously */      http_cache_destroy_entry (slot);      slot = http_cache_create_entry ();    }  svz_hash_put (http_cache, file, slot);  slot->file = svz_strdup (file);  if ((slot->next = http_cache_first) == NULL)    http_cache_last = slot;  else    http_cache_first->prev = slot;  http_cache_first = slot;  /*   * initialize the cache entry for the cache file reader: cachebuffer    * is not allocated yet and current cache length is zero   */  http_cache_reset (cache);  cache->entry = slot;  http_cache_consistency ();  return 0;}/* * Refresh a certain cache entry for reusing it afterwards. So we do not * destroy the entry, but the actual cache content. */voidhttp_refresh_cache (http_cache_t *cache){  svz_free_and_zero (cache->entry->buffer);  cache->entry->ready = 0;  cache->entry->hits = 0;  cache->entry->usage = 0;  cache->size = 0;  cache->buffer = NULL;}/* * Send a complete cache entry to a http connection. */inthttp_cache_write (svz_socket_t *sock){  int num_written;  int do_write;  http_socket_t *http;  http_cache_t *cache;  /* get additional cache and http structures */  http = sock->data;  cache = http->cache;  assert (cache->entry);  do_write = cache->size;  if (do_write > (SOCK_MAX_WRITE << 5))    do_write = (SOCK_MAX_WRITE << 5);  num_written = send (sock->sock_desc, cache->buffer, do_write, 0);  if (num_written > 0)    {      sock->last_send = time (NULL);      cache->buffer += num_written;      cache->size -= num_written;      http->length += num_written;    }  else if (num_written < 0)    {      svz_log (LOG_ERROR, "cache: send: %s\n", NET_ERROR);      if (svz_errno == SOCK_UNAVAILABLE)	{	  sock->unavailable = time (NULL) + RELAX_FD_TIME;	  num_written = 0;	}    }  /*   * Check if the http cache has (success)fully been sent.   * If yes then return non-zero in order to shutdown the   * socket SOCK.   */  if (cache->size <= 0)    {#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "cache: file successfully sent\n");#endif      num_written = http_keep_alive (sock);    }    /*   * Return a non-zero value if an error occurred.   */  return (num_written < 0) ? -1 : 0;}/* * Do just the same as the http_file_read() but additionally copy * the data into the cache entry. */inthttp_cache_read (svz_socket_t *sock){  int num_read;  int do_read;  http_socket_t *http;  http_cache_t *cache;  /* get additional cache and http structures */  http = sock->data;  cache = http->cache;  do_read = sock->send_buffer_size - sock->send_buffer_fill;  /*    * This means the send buffer is currently full, we have to    * wait until some data has been send via the socket.   */  if (do_read <= 0)    {      return 0;    }  /*   * Try to read as much data as possible from the file.   */#ifndef __MINGW32__  num_read = read (sock->file_desc,		   sock->send_buffer + sock->send_buffer_fill, do_read);#else  if (!ReadFile ((HANDLE) sock->file_desc,		 sock->send_buffer + sock->send_buffer_fill,		 do_read, (DWORD *) &num_read, NULL))    {      num_read = -1;    }#endif    /* Read error occurred. */  if (num_read < 0)    {#ifndef __MINGW32__      svz_log (LOG_ERROR, "cache: read: %s\n", SYS_ERROR);#else      svz_log (LOG_ERROR, "cache: ReadFile: %s\n", SYS_ERROR);#endif      /* release the actual cache entry previously reserved */      if (cache->size > 0) 	{	  svz_free (cache->buffer);	  http_cache_reset (cache);	}      return -1;    }  /* Data has been read. */  else if (num_read > 0)    {      /*        * Reserve some more memory and then copy the gained data       * to the cache entry.       */      cache->buffer = svz_realloc (cache->buffer, cache->size + num_read);      memcpy (cache->buffer + cache->size,	      sock->send_buffer + sock->send_buffer_fill, num_read);      cache->size += num_read;      sock->send_buffer_fill += num_read;      http->filelength -= num_read;      http->length += num_read;    }  /* Bogus file. File size from stat() was not true. */  if (num_read == 0 && http->filelength != 0)    {      cache->entry->size = cache->size;      cache->entry->buffer = cache->buffer;      cache->entry->ready = 42;      http_cache_reset (cache);      return -1;    }  /* EOF reached and set the appropriate flags */  if (http->filelength <= 0)    {#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "cache: `%s' successfully read\n", 	       cache->entry->file);#endif      /* fill in the actual cache entry */      cache->entry->size = cache->size;      cache->entry->buffer = cache->buffer;      cache->entry->ready = 42;      http_cache_reset (cache);      /* set flags and reassign default reader */      sock->read_socket = svz_tcp_read_socket;      sock->userflags |= HTTP_FLAG_DONE;      sock->flags &= ~SOCK_FLAG_FILE;    }  return 0;}#else /* ENABLE_HTTP_PROTO */ int http_cache_dummy; /* Silence compiler. */#endif /* not ENABLE_HTTP_PROTO */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -