summaryrefslogtreecommitdiffstats
path: root/cpukit/shttpd/defs.h
blob: fef5ecefc4673bb5cb0224f6740dda68f56b688a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/*
 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
 * All rights reserved
 *
 * "THE BEER-WARE LICENSE" (Revision 42):
 * Sergey Lyubka wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.
 */

#ifndef DEFS_HEADER_DEFINED
#define	DEFS_HEADER_DEFINED

#include "std_includes.h"
#include "llist.h"
#include "io.h"
#include "shttpd.h"
#include "md5.h"

#define	VERSION		"1.37"		/* Version			*/

#ifndef CONFIG
#define	CONFIG		"shttpd.conf"	/* Configuration file		*/
#endif /* CONFIG */

#define	HTPASSWD	".htpasswd"	/* Passwords file name		*/
#define	DFLT_IO_SIZ	"16384"		/* Default max request size	*/
#define	HTTP_PORT	"80"		/* Default listening port	*/
#define	INDEX_FILES	"index.html index.htm index.php index.cgi"
#define	CGI_EXT		".cgi .pl .php"	/* Default CGI extensions	*/
#define	REALM		"mydomain.com"	/* Default authentication realm	*/
#define	DELIM_CHARS	" ,"		/* Separators for lists		*/

#define	EXPIRE_TIME	3600		/* Expiration time, seconds	*/
#define	ENV_MAX		4096		/* Size of environment block	*/
#define	CGI_ENV_VARS	64		/* Maximum vars passed to CGI	*/
#define	URI_MAX		32768		/* Maximum URI size		*/
#define	MIN_REQ_LEN	16		/* "GET / HTTP/1.1\n\n"		*/

#define	NELEMS(ar)	(sizeof(ar) / sizeof(ar[0]))

#ifdef _DEBUG
#define	DBG(x)	do { printf x ; putchar('\n'); fflush(stdout); } while (0)
#else
#define	DBG(x)
#endif /* DEBUG */

#ifdef EMBEDDED
#include "shttpd.h"
#endif /* EMBEDDED */

/*
 * Darwin prior to 7.0 and Win32 do not have socklen_t
 */
#ifdef NO_SOCKLEN_T
typedef int socklen_t;
#endif /* NO_SOCKLEN_T */

/*
 * For parsing. This guy represents a substring.
 */
struct vec {
	const char	*ptr;
	int		len;
};

enum {METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_DELETE, METHOD_HEAD};
enum {HDR_DATE, HDR_INT, HDR_STRING};	/* HTTP header types		*/
enum {E_FATAL = 1, E_LOG = 2};		/* Flags for elog() function	*/
typedef unsigned long big_int_t;	/* Type for Content-Length	*/
	
/*
 * Unified socket address
 */
struct usa {
	socklen_t len;
	union {
		struct sockaddr	sa;
		struct sockaddr_in sin;
	} u;
};

/*
 * This thing is aimed to hold values of any type.
 * Used to store parsed headers' values.
 */
union variant {
	char		*v_str;
	int		v_int;
	big_int_t	v_big_int;
	time_t		v_time;
	void		(*v_func)(void);
	void		*v_void;
	struct vec	v_vec;
};

/*
 * This structure is used to hold mime types and associated file extensions.
 */
struct mime_type {
	const char	*ext;
	int		ext_len;
	const char	*mime;
};

struct mime_type_link {
	struct llhead	link;
	char		*ext;
	int		ext_len;
	char		*mime;
};

/*
 * This is used only in embedded configuration. This structure holds a
 * registered URI, associated callback function with callback data.
 * For non-embedded compilation shttpd_callback_t is not defined, so
 * we use union variant to keep the compiler silent.
 */
struct registered_uri {
	struct llhead	link;
	const char	*uri;
	union variant	callback;
	void		*callback_data;
};

/*
 * User may bind a passwords file to any URI. This makes that URI password
 * protected: anybody who accesses that URI will be asked to authorize.
 */
struct uri_auth {
	struct llhead	link;
	const char	*uri;
	const char	*file_name;
	size_t		uri_len;
};

/*
 * User may want to handle certain errors. This structure holds the
 * handlers for corresponding error codes.
 */
struct error_handler {
	struct llhead	link;
	int		code;
	union variant	callback;
	void		*callback_data;
};

struct http_header {
	int		len;		/* Header name length		*/
	int		type;		/* Header type			*/
	size_t		offset;		/* Value placeholder		*/
	const char	*name;		/* Header name			*/
};

/*
 * This guy holds parsed HTTP headers
 */
struct headers {
	union variant	cl;		/* Content-Length:		*/
	union variant	ct;		/* Content-Type:		*/
	union variant	connection;	/* Connection:			*/
	union variant	ims;		/* If-Modified-Since:		*/
	union variant	user;		/* Remote user name		*/
	union variant	auth;		/* Authorization		*/
	union variant	useragent;	/* User-Agent:			*/
	union variant	referer;	/* Referer:			*/
	union variant	cookie;		/* Cookie:			*/
	union variant	location;	/* Location:			*/
	union variant	range;		/* Range:			*/
	union variant	status;		/* Status:			*/
	union variant	transenc;	/* Transfer-Encoding:		*/
};

/* Must go after union variant definition */
#include "ssl.h"

/*
 * The communication channel
 */
union channel {
	int		fd;		/* Regular static file		*/
	int		sock;		/* Connected socket		*/
	struct {
		int		sock;	/* XXX important. must be first	*/
		SSL		*ssl;	/* shttpd_poll() assumes that	*/
	} ssl;				/* SSL-ed socket		*/
	struct {
		DIR	*dirp;
		char	*path;
	} dir;				/* Opened directory		*/
	struct {
		void		*state;	/* For keeping state		*/
		union variant	func;	/* User callback function	*/
		void		*data;	/* User defined parameters	*/
	} emb;				/* Embedded, user callback	*/
};

struct stream;

/*
 * IO class descriptor (file, directory, socket, SSL, CGI, etc)
 * These classes are defined in io_*.c files.
 */
struct io_class {
	const char *name;
	int (*read)(struct stream *, void *buf, size_t len);
	int (*write)(struct stream *, const void *buf, size_t len);
	void (*close)(struct stream *);
};

/*
 * Data exchange stream. It is backed by some communication channel:
 * opened file, socket, etc. The 'read' and 'write' methods are
 * determined by a communication channel.
 */
struct stream {
	struct conn		*conn;
	union channel		chan;		/* Descriptor		*/
	struct io		io;		/* IO buffer		*/
	const struct io_class	*io_class;	/* IO class		*/
	int			nread_last;	/* Bytes last read	*/
	int			headers_len;
	big_int_t		content_len;
	unsigned int		flags;
#define	FLAG_HEADERS_PARSED	1
#define	FLAG_SSL_ACCEPTED	2
#define	FLAG_R			4		/* Can read in general	*/
#define	FLAG_W			8		/* Can write in general	*/
#define	FLAG_CLOSED		16
#define	FLAG_DONT_CLOSE		32
#define	FLAG_ALWAYS_READY	64		/* File, dir, user_func	*/
};

struct conn {
	struct llhead	link;		/* Connections chain		*/
	struct shttpd_ctx *ctx;		/* Context this conn belongs to */
	struct usa	sa;		/* Remote socket address	*/
	time_t		birth_time;	/* Creation time		*/
	time_t		expire_time;	/* Expiration time		*/

	int		status;		/* Reply status code		*/
	int		method;		/* Request method		*/
	char		*uri;		/* Decoded URI			*/
	unsigned long	major_version;	/* Major HTTP version number    */
	unsigned long	minor_version;	/* Minor HTTP version number    */
	char		*request;	/* Request line			*/
	char		*headers;	/* Request headers		*/
	char		*query;		/* QUERY_STRING part of the URI	*/
	char		*path_info;	/* PATH_INFO thing		*/
	const char	*mime_type;	/* Mime type			*/

	struct headers	ch;		/* Parsed client headers	*/

	struct stream	loc;		/* Local stream			*/
	struct stream	rem;		/* Remote stream		*/
};


/*
 * SHTTPD context
 */
struct shttpd_ctx {
	time_t		start_time;	/* Start time			*/
	int		nactive;	/* # of connections now		*/
	unsigned long	nrequests;	/* Requests made		*/
	uint64_t	in, out;	/* IN/OUT traffic counters	*/
#if !defined(NO_SSL)
	SSL_CTX		*ssl_ctx;	/* SSL context			*/
#endif /* NO_SSL */
	struct llhead	connections;	/* List of connections		*/

	struct llhead	mime_types;	/* Known mime types		*/
	struct llhead	registered_uris;/* User urls			*/
	struct llhead	uri_auths;	/* User auth files		*/
	struct llhead	error_handlers;	/* Embedded error handlers	*/

	FILE	*access_log;		/* Access log stream		*/
	FILE	*error_log;		/* Error log stream		*/
	char	*put_auth_file;		/* PUT auth file		*/
	char	*document_root;		/* Document root		*/
	char	*index_files;		/* Index files			*/
	char	*aliases;		/* Aliases			*/
	char	*mime_file;		/* Mime types file		*/
#if !defined(NO_CGI)
	char	*cgi_vars;		/* CGI environment variables	*/
	char	*cgi_extensions;	/* CGI extensions		*/
	char	*cgi_interpreter;	/* CGI script interpreter	*/
#endif /* NO_CGI */
	char	*auth_realm;		/* Auth realm			*/
	char	*global_passwd_file;	/* Global passwords file	*/
	char	*uid;			/* Run as user			*/
	int	port;			/* Listening port		*/
	int	dirlist;		/* Directory listing		*/
	int	gui;			/* Show GUI flag		*/
	int	auto_start;		/* Start on OS boot		*/
	int	io_buf_size;		/* IO buffer size		*/
	int	inetd_mode;		/* Inetd flag			*/
#if defined(_WIN32)
	CRITICAL_SECTION mutex;		/* For MT case		*/
	HANDLE		ev[2];		/* For thread synchronization */
#elif defined(__rtems__)
	rtems_id         mutex;
#endif /* _WIN32 */
};

struct listener {
	struct llhead	link;
	struct shttpd_ctx *ctx;		/* Context that socket belongs	*/
	int		sock;		/* Listening socket		*/
};

/* Option setter function */
typedef void (*optset_t)(struct shttpd_ctx *, void *ptr, const char *string);
struct opt {
	int		sw;		/* Command line switch		*/
	const char	*name;		/* Option name in config file	*/
	const char	*desc;		/* Description			*/
	optset_t	setter;		/* Option setter function	*/
	size_t		ofs;		/* Value offset in context	*/
	const char	*arg;		/* Argument format		*/
	const char	*def;		/* Default option value		*/
	unsigned int	flags;		/* Flags			*/
#define	OPT_BOOL	1
#define	OPT_INT		2
#define	OPT_FILE	4
#define	OPT_DIR		8
#define	OPT_ADVANCED	16
};

extern const struct opt options[];

/*
 * In SHTTPD, list of values are represented as comma or space separated
 * string. For example, list of CGI extensions can be represented as
 * ".cgi,.php,.pl", or ".cgi .php .pl". The macro that follows allows to
 * loop through the individual values in that list.
 * A "const char *" pointer and size_t variable must be passed to the macro.
 * Spaces or commas can be used as delimiters (macro DELIM_CHARS)
 */
#define	FOR_EACH_WORD_IN_LIST(s,len)	\
	for (; s != NULL && (len = strcspn(s, DELIM_CHARS)) != 0; s += len + 1)

/*
 * shttpd.c
 */
extern time_t		current_time;	/* Current UTC time		*/
extern int		tz_offset;	/* Offset from GMT time zone	*/
extern const struct vec known_http_methods[];

extern void	stop_stream(struct stream *stream);
extern void	decode_url_encoded_string(const char *, int, char *dst, int);
extern void	send_server_error(struct conn *, int code, const char *reason);
extern int	get_headers_len(const char *buf, size_t buflen);
extern void	parse_headers(const char *s, int len, struct headers *parsed);

/*
 * mime_type.c
 */
extern const char *get_mime_type(struct shttpd_ctx *, const char *uri, int len);
extern void	set_mime_types(struct shttpd_ctx *ctx, const char *path);

/*
 * config.c
 */
extern void	usage(const char *prog);
extern struct shttpd_ctx *init_from_argc_argv(const char *, int, char *[]);

/*
 * log.c
 */
extern void	elog(int flags, struct conn *c, const char *fmt, ...);
extern void	log_access(FILE *fp, const struct conn *c);

/*
 * string.c
 */
#ifndef HAVE_STRLCPY
extern void	my_strlcpy(register char *, register const char *, size_t);
#else
#include <string.h>
#define my_strlcpy(d,s,l) strlcpy(d,s,l)
#endif

#ifndef HAVE_STRNCASECMP
extern int	my_strncasecmp(register const char *,
		register const char *, size_t);
#else
#ifdef __rtems__
/* strncasecmp should be in strings.h, but newlib has it in <string.h> */
#include <string.h>
#else
#include <strings.h>
#endif
#define my_strncasecmp(s1,s2,l) strncasecmp(s1,s2,l)
#endif

#ifndef HAVE_STRNDUP
extern char	*my_strndup(const char *ptr, size_t len);
#else
#include <string.h>
#define my_strndup(x,l) strndup((x),(l))
#endif

#ifndef HAVE_STRDUP
extern char	*my_strdup(const char *str);
#else
#include <string.h>
#define my_strdup(x) strdup(x)
#endif
extern int	my_snprintf(char *buf, size_t buflen, const char *fmt, ...);

/*
 * compat_*.c
 */
extern void	set_close_on_exec(int fd);
extern int	set_non_blocking_mode(int fd);
#if __rtems__
#define my_stat	stat
#define my_open open
#define my_remove remove
#define my_rename rename
#define my_mkdir mkdir
#define my_getcwd getcwd
#else
extern int	my_stat(const char *, struct stat *stp);
extern int	my_open(const char *, int flags, int mode);
extern int	my_remove(const char *);
extern int	my_rename(const char *, const char *);
extern int	my_mkdir(const char *, int);
extern char *	my_getcwd(char *, int);
#endif
extern int	spawn_process(struct conn *c, const char *prog,
		char *envblk, char *envp[], int sock, const char *dir);

/*
 * io_*.c
 */
extern const struct io_class	io_file;
extern const struct io_class	io_socket;
extern const struct io_class	io_ssl;
extern const struct io_class	io_cgi;
extern const struct io_class	io_dir;
extern const struct io_class	io_embedded;

extern int	put_dir(const char *path);
extern void	get_dir(struct conn *c);
extern void	get_file(struct conn *c, struct stat *stp);
extern void	ssl_handshake(struct stream *stream);
extern void	setup_embedded_stream(struct conn *, union variant, void *);
extern struct registered_uri *is_registered_uri(struct shttpd_ctx *,
		const char *uri);

/*
 * auth.c
 */
extern int	check_authorization(struct conn *c, const char *path);
extern int	is_authorized_for_put(struct conn *c);
extern void	send_authorization_request(struct conn *c);
extern int	edit_passwords(const char *fname, const char *domain,
		const char *user, const char *pass);

/*
 * cgi.c
 */
extern int	is_cgi(struct shttpd_ctx *ctx, const char *path);
extern int	run_cgi(struct conn *c, const char *prog);
extern void	do_cgi(struct conn *c);

#define CGI_REPLY	"HTTP/1.1     OK\r\n"
#define	CGI_REPLY_LEN	(sizeof(CGI_REPLY) - 1)

#endif /* DEFS_HEADER_DEFINED */