You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
7.0 KiB
C

#include <sys/stat.h>
#ifdef USE_THREADS
# include <pthread.h>
#endif
#define STATE_READ_HEADER 1
#define STATE_PARSE_HEADER 2
#define STATE_WRITE_HEADER 3
#define STATE_WRITE_BODY 4
#define STATE_WRITE_FILE 5
#define STATE_WRITE_RANGES 6
#define STATE_FINISHED 7
#define STATE_KEEPALIVE 8
#define STATE_CLOSE 9
#define STATE_CGI_HEADER 10
#define STATE_CGI_BODY_IN 11
#define STATE_CGI_BODY_OUT 12
#ifdef USE_SSL
# include <openssl/ssl.h>
#endif
#define MAX_HEADER 4096
#define MAX_PATH 2048
#define MAX_HOST 64
#define MAX_MISC 16
#define BR_HEADER 512
#define S1(str) #str
#define S(str) S1(str)
#define RFC1123 "%a, %d %b %Y %H:%M:%S GMT"
struct DIRCACHE {
char path[1024];
char mtime[40];
time_t add;
char *html;
int length;
#ifdef USE_THREADS
pthread_mutex_t lock_refcount;
pthread_mutex_t lock_reading;
pthread_cond_t wait_reading;
#endif
int refcount;
int reading;
struct DIRCACHE *next;
};
struct REQUEST {
int fd; /* socket handle */
int state; /* what to to ??? */
time_t ping; /* last read/write (for timeouts) */
int keep_alive;
int tcp_cork;
struct sockaddr_storage peer; /* client (log) */
char peerhost[MAX_HOST+1];
char peerserv[MAX_MISC+1];
/* request */
char hreq[MAX_HEADER+1]; /* request header */
int lreq; /* request length */
int hdata; /* data in hreq */
char type[MAX_MISC+1]; /* req type */
char hostname[MAX_HOST+1]; /* hostname */
char uri[MAX_PATH+1]; /* req uri */
char path[MAX_PATH+1]; /* file path */
char query[MAX_PATH+1]; /* query string */
int major,minor; /* http version */
char auth[64];
struct strlist *header;
char *if_modified;
char *if_unmodified;
char *if_range;
char *range_hdr;
int ranges;
off_t *r_start;
off_t *r_end;
char *r_head;
int *r_hlen;
/* response */
int status; /* status code (log) */
int bc; /* byte counter (log) */
char hres[MAX_HEADER+1]; /* response header */
int lres; /* header length */
char *mime; /* mime type */
char *body;
off_t lbody;
int bfd; /* file descriptor */
struct stat bst; /* file info */
char mtime[40]; /* RFC 1123 */
off_t written;
int head_only;
int rh,rb;
struct DIRCACHE *dir;
/* CGI */
int cgipid;
int cgipipe;
char cgibuf[MAX_HEADER+1];
int cgilen,cgipos;
#ifdef USE_SSL
/* SSL */
SSL *ssl_s;
#endif
/* linked list */
struct REQUEST *next;
};
/* --- string lists --------------------------------------------- */
struct strlist {
struct strlist *next;
char *line;
int free_the_mallocs;
};
/* add element (list head) */
static void inline
list_add(struct strlist **list, char *line, int free_the_mallocs)
{
struct strlist *elem = malloc(sizeof(struct strlist));
memset(elem,0,sizeof(struct strlist));
elem->next = *list;
elem->line = line;
elem->free_the_mallocs = free_the_mallocs;
*list = elem;
}
/* free whole list */
static void inline
list_free(struct strlist **list)
{
struct strlist *elem,*next;
for (elem = *list; NULL != elem; elem = next) {
next = elem->next;
if (elem->free_the_mallocs)
free(elem->line);
free(elem);
}
*list = NULL;
}
/* --- main.c --------------------------------------------------- */
extern int debug;
extern int tcp_port;
extern int max_dircache;
extern int virtualhosts;
extern int canonicalhost;
extern int do_chroot;
extern char *server_name;
extern char *indexhtml;
extern char *cgipath;
extern char *doc_root;
extern char server_host[];
extern char *userpass;
extern char *userdir;
extern int lifespan;
extern int no_listing;
extern time_t now;
extern int have_tty;
#ifdef USE_SSL
extern int with_ssl;
extern SSL_CTX *ctx;
extern BIO *sbio, *ssl_bio;
extern char *certificate;
extern char *password;
#endif
void xperror(int loglevel, char *txt, char *peerhost);
void xerror(int loglevel, char *txt, char *peerhost);
static void inline close_on_exec(int fd)
{
if (cgipath)
fcntl(fd,F_SETFD,FD_CLOEXEC);
}
/* --- ssl.c ---------------------------------------------------- */
#ifdef USE_SSL
extern int ssl_read(struct REQUEST *req, char *buf, int len);
extern int ssl_write(struct REQUEST *req, char *buf, int len);
extern int ssl_blk_write(struct REQUEST *req, off_t offset, size_t len);
extern void init_ssl(void);
extern void open_ssl_session(struct REQUEST *req);
#endif
/* --- request.c ------------------------------------------------ */
void read_request(struct REQUEST *req, int pipelined);
void parse_request(struct REQUEST *req);
/* --- response.c ----------------------------------------------- */
extern char *h200,*h206,*h302,*h304;
extern char *h403,*b403;
extern char *h404,*b404;
extern char *h500,*b500;
extern char *h501,*b501;
void mkerror(struct REQUEST *req, int status, int ka);
void mkredirect(struct REQUEST *req);
void mkheader(struct REQUEST *req, int status);
void mkcgi(struct REQUEST *req, char *status, struct strlist *header);
void write_request(struct REQUEST *req);
/* --- ls.c ----------------------------------------------------- */
void init_quote(void);
char* quote(unsigned char *path, int maxlength);
struct DIRCACHE *get_dir(struct REQUEST *req, char *filename);
void free_dir(struct DIRCACHE *dir);
/* --- mime.c --------------------------------------------------- */
char* get_mime(char *file);
void init_mime(char *file, char *def);
/* --- cgi.c ---------------------------------------------------- */
void cgi_request(struct REQUEST *req);
void cgi_read_header(struct REQUEST *req);
/* -------------------------------------------------------------- */
#ifdef USE_THREADS
# define INIT_LOCK(mutex) pthread_mutex_init(&mutex,NULL)
# define FREE_LOCK(mutex) pthread_mutex_destroy(&mutex)
# define DO_LOCK(mutex) pthread_mutex_lock(&mutex)
# define DO_UNLOCK(mutex) pthread_mutex_unlock(&mutex)
# define INIT_COND(cond) pthread_cond_init(&cond,NULL)
# define FREE_COND(cond) pthread_cond_destroy(&cond)
# define BCAST_COND(cond) pthread_cond_broadcast(&cond);
# define WAIT_COND(cond,mutex) pthread_cond_wait(&cond,&mutex);
#else
# define INIT_LOCK(mutex) /* nothing */
# define FREE_LOCK(mutex) /* nothing */
# define DO_LOCK(mutex) /* nothing */
# define DO_UNLOCK(mutex) /* nothing */
# define INIT_COND(cond) /* nothing */
# define FREE_COND(cond) /* nothing */
# define BCAST_COND(cond) /* nothing */
# define WAIT_COND(cond,mutex) /* nothing */
#endif