Diff

Differences From Artifact [91c2968a74]:

To Artifact [4157b8b146]:


    28     28   
    29     29   /* Default values */
    30     30   #define PORT 80
    31     31   #define THREAD_COUNT 5
    32     32   #define BIND_ADDR "::"
    33     33   #define CACHE_SIZE 8209
    34     34   #define LOG_FILE "-"
           35  +
           36  +/* Configuration options that work threads need to be aware of */
           37  +struct filed_options {
           38  +	int vhosts_enabled;
           39  +};
    35     40   
    36     41   /* Arguments for worker threads */
    37     42   struct filed_worker_thread_args {
    38     43   	int fd;
           44  +	struct filed_options options;
    39     45   };
    40     46   
    41     47   /* Arguments for logging threads */
    42     48   struct filed_logging_thread_args {
    43     49   	FILE *fp;
    44     50   };
    45     51   
................................................................................
    55     61   	char etag[64];
    56     62   };
    57     63   
    58     64   /* Request variables */
    59     65   struct filed_http_request {
    60     66   	/** Buffers **/
    61     67   	struct filed_fileinfo fileinfo;
    62         -	char tmpbuf[1010];
           68  +	char tmpbuf[FILED_PATH_BUFFER_SIZE];
    63     69   
    64     70   	/** HTTP Request information **/
    65     71   	/*** Type of request (HEAD or GET) ***/
    66     72   	enum {
    67     73   		FILED_REQUEST_METHOD_GET,
    68     74   		FILED_REQUEST_METHOD_HEAD
    69     75   	} method;
................................................................................
    73     79   
    74     80   	struct {
    75     81   		struct {
    76     82   			int present;
    77     83   			off_t offset;   /*** Range start ***/
    78     84   			off_t length;   /*** Range length ***/
    79     85   		} range;
           86  +
           87  +		struct {
           88  +			int present;
           89  +			char host[FILED_PATH_BUFFER_SIZE];
           90  +		} host;
    80     91   	} headers;
    81     92   };
    82     93   
    83     94   /* Log record */
    84     95   struct filed_log_entry {
    85     96   	/* Type of log entry */
    86     97   	enum {
................................................................................
   623    634   
   624    635   	pthread_mutex_unlock(&cache->mutex);
   625    636   
   626    637   	return(buffer);
   627    638   }
   628    639   
   629    640   /* Process an HTTP request and return the path requested */
   630         -static struct filed_http_request *filed_get_http_request(FILE *fp, struct filed_http_request *buffer_st) {
          641  +static struct filed_http_request *filed_get_http_request(FILE *fp, struct filed_http_request *buffer_st, struct filed_options *options) {
   631    642   	char *method, *path;
   632    643   	char *buffer, *workbuffer, *workbuffer_next;
   633    644   	char *fgets_ret;
   634    645   	size_t buffer_len;
   635    646   	off_t range_start, range_end, range_length;
   636    647   	int range_request;
          648  +	int snprintf_ret;
   637    649   	int i;
   638    650   
          651  +	/* Set to default values */
   639    652   	range_start = 0;
   640    653   	range_end   = 0;
   641    654   	range_request = 0;
   642    655   	range_length = -1;
          656  +	buffer_st->headers.host.present = 0;
   643    657   
   644    658   	buffer = buffer_st->tmpbuf;
   645    659   	buffer_len = sizeof(buffer_st->tmpbuf);
   646    660   
   647    661   	fgets_ret = fgets(buffer, buffer_len, fp);
   648    662   	if (fgets_ret == NULL) {
   649    663   		return(NULL);
................................................................................
   658    672   
   659    673   	*buffer = '\0';
   660    674   	buffer++;
   661    675   
   662    676   	path = buffer;
   663    677   
   664    678   	/* Terminate path component */
   665         -	buffer = strpbrk(buffer, "\r\n ");
          679  +	buffer = strpbrk(path, "\r\n ");
   666    680   	if (buffer != NULL) {
   667    681   		*buffer = '\0';
   668    682   		buffer++;
   669    683   	}
   670    684   
   671    685   	/* We only handle the "GET" and "HEAD' methods */
   672    686   	if (strcasecmp(method, "head") != 0) {
................................................................................
   709    723   					workbuffer++;
   710    724   
   711    725   					if (*workbuffer != '\r' && *workbuffer != '\n') {
   712    726   						range_end = strtoull(workbuffer, &workbuffer_next, 10);
   713    727   					}
   714    728   				}
   715    729   			}
          730  +		} else if (strncasecmp(buffer, "Host: ", 5) == 0) {
          731  +			buffer_st->headers.host.present = 1;
          732  +
          733  +			workbuffer = strpbrk(buffer + 5, "\r\n:");
          734  +			if (workbuffer != NULL) {
          735  +				*workbuffer = '\0';
          736  +			}
          737  +
          738  +			workbuffer = buffer + 5;
          739  +			while (*workbuffer == ' ') {
          740  +				workbuffer++;
          741  +			}
          742  +
          743  +			strcpy(buffer_st->headers.host.host, workbuffer);
   716    744   		}
   717    745   
   718    746   		if (memcmp(buffer, "\r\n", 2) == 0) {
   719    747   			break;
   720    748   		}
   721    749   	}
   722    750   
................................................................................
   735    763   		);
   736    764   	}
   737    765   
   738    766   	/* Fill up structure to return */
   739    767   	buffer_st->headers.range.present = range_request;
   740    768   	buffer_st->headers.range.offset  = range_start;
   741    769   	buffer_st->headers.range.length  = range_length;
          770  +
          771  +	/* If vhosts are enabled, compute new path */
          772  +	if (options->vhosts_enabled) {
          773  +		if (buffer_st->headers.host.present == 1) {
          774  +			buffer = buffer_st->tmpbuf;
          775  +			buffer_len = sizeof(buffer_st->tmpbuf);
          776  +
          777  +			snprintf_ret = snprintf(buffer, buffer_len, "/%s%s%s",
          778  +				buffer_st->headers.host.host,
          779  +				buffer_st->path[0] == '/' ? "" : "/",
          780  +				buffer_st->path
          781  +			);
          782  +			if (snprintf_ret >= 0) {
          783  +				if (((unsigned int) snprintf_ret) < buffer_len) {
          784  +					strcpy(buffer_st->path, buffer);
          785  +				}
          786  +			}
          787  +		}
          788  +	}
   742    789   
   743    790   	return(buffer_st);
   744    791   }
   745    792   
   746    793   /* Return an error page */
   747    794   static void filed_error_page(FILE *fp, const char *date_current, int error_number, int method) {
   748    795   	char *error_string = "<html><head><title>ERROR</title></head><body>Unable to process request</body></html>";
................................................................................
   760    807   		fprintf(fp, "%s", error_string);
   761    808   	}
   762    809   
   763    810   	return;
   764    811   }
   765    812   
   766    813   /* Handle a single request from a client */
   767         -static void filed_handle_client(int fd, struct filed_http_request *request, struct filed_log_entry *log) {
          814  +static void filed_handle_client(int fd, struct filed_http_request *request, struct filed_log_entry *log, struct filed_options *options) {
   768    815   	struct filed_fileinfo *fileinfo;
   769    816   	ssize_t sendfile_ret;
   770    817   	size_t sendfile_size;
   771    818   	off_t sendfile_offset, sendfile_sent, sendfile_len;
   772    819   	char *path;
   773    820   	char *date_current, date_current_b[64];
   774    821   	int http_code;
................................................................................
   781    828   	fp = fdopen(fd, "w+b");
   782    829   	if (fp == NULL) {
   783    830   		close(fd);
   784    831   
   785    832   		return;
   786    833   	}
   787    834   
   788         -	request = filed_get_http_request(fp, request);
          835  +	request = filed_get_http_request(fp, request, options);
   789    836   
   790    837   	if (request == NULL) {
   791    838   		filed_error_page(fp, date_current, 500, FILED_REQUEST_METHOD_GET);
   792    839   
   793    840   		log->buffer[0] = '\0';
   794    841   		log->http_code = 500;
   795    842   		log->reason = "format";
................................................................................
   958   1005   }
   959   1006   
   960   1007   /* Handle incoming connections */
   961   1008   static void *filed_worker_thread(void *arg_v) {
   962   1009   	struct filed_worker_thread_args *arg;
   963   1010   	struct filed_http_request request;
   964   1011   	struct filed_log_entry *log, local_dummy_log;
         1012  +	struct filed_options *options;
   965   1013   	struct sockaddr_in6 addr;
   966   1014   	socklen_t addrlen;
   967   1015   	int failure_count = 0, max_failure_count = FILED_MAX_FAILURE_COUNT;
   968   1016   	int master_fd, fd;
   969   1017   
   970   1018   	/* Read arguments */
   971   1019   	arg = arg_v;
   972   1020   
   973   1021   	master_fd = arg->fd;
         1022  +	options = &arg->options;
   974   1023   
   975   1024   	while (1) {
   976   1025   		/* Failure loop prevention */
   977   1026   		if (failure_count > max_failure_count) {
   978   1027   			break;
   979   1028   		}
   980   1029   
................................................................................
  1009   1058   		}
  1010   1059   		log->port = addr.sin6_port;
  1011   1060   
  1012   1061   		/* Reset failure count*/
  1013   1062   		failure_count = 0;
  1014   1063   
  1015   1064   		/* Handle socket */
  1016         -		filed_handle_client(fd, &request, log);
         1065  +		filed_handle_client(fd, &request, log, options);
  1017   1066   	}
  1018   1067   
  1019   1068   	/* Report error */
  1020   1069   	filed_log_msg("THREAD_DIED ABNORMAL");
  1021   1070   
  1022   1071   	return(NULL);
  1023   1072   
  1024   1073   	/* local_dummy_log is only used if FILED_DONT_LOG is enabled, otherwise it's not used, but the compiler hates that idea. */
  1025   1074   	local_dummy_log.type = 0;
  1026   1075   	local_dummy_log.type = local_dummy_log.type;
  1027   1076   }
  1028   1077   
  1029   1078   /* Create worker threads */
  1030         -static int filed_worker_threads_init(int fd, int thread_count) {
         1079  +static int filed_worker_threads_init(int fd, int thread_count, struct filed_options *options) {
  1031   1080   	struct filed_worker_thread_args *arg;
  1032   1081   	pthread_t threadid;
  1033   1082   	int pthread_ret;
  1034   1083   	int i;
  1035   1084   
  1036   1085   	for (i = 0; i < thread_count; i++) {
  1037   1086   		arg = malloc(sizeof(*arg));
  1038   1087   
  1039   1088   		arg->fd = fd;
         1089  +		memcpy(&arg->options, options, sizeof(*options));
  1040   1090   
  1041   1091   		pthread_ret = pthread_create(&threadid, NULL, filed_worker_thread, arg);
  1042   1092   		if (pthread_ret != 0) {
  1043   1093   			return(-1);
  1044   1094   		}
  1045   1095   	}
  1046   1096   
................................................................................
  1054   1104   	}
  1055   1105   
  1056   1106   	fprintf(output, "Usage: filed [<options>]\n");
  1057   1107   	fprintf(output, "  Options:\n");
  1058   1108   	fprintf(output, "      -h, --help\n");
  1059   1109   	fprintf(output, "      -d, --daemon\n");
  1060   1110   	fprintf(output, "      -v, --version\n");
         1111  +	fprintf(output, "      -V, --vhost\n");
  1061   1112   	fprintf(output, "      -b <address>, --bind <address>\n");
  1062   1113   	fprintf(output, "      -p <port>, --port <port>\n");
  1063   1114   	fprintf(output, "      -t <count>, --threads <count>\n");
  1064   1115   	fprintf(output, "      -c <entries>, --cache <entries>\n");
  1065   1116   	fprintf(output, "      -l <file>, --log <file>\n");
  1066   1117   	fprintf(output, "      -u <user>, --user <user>\n");
  1067   1118   	fprintf(output, "      -r <directory>, --root <directory>\n");
................................................................................
  1071   1122   		fprintf(output, "  Usage:\n");
  1072   1123   		fprintf(output, "      -h (or --help) prints this usage information.\n");
  1073   1124   		fprintf(output, "\n");
  1074   1125   		fprintf(output, "      -d (or --daemon) instructs filed to become a daemon after initializing\n");
  1075   1126   		fprintf(output, "                       the listening TCP socket and log files.\n");
  1076   1127   		fprintf(output, "\n");
  1077   1128   		fprintf(output, "      -v (or --version) instructs filed print out the version number and exit.\n");
         1129  +		fprintf(output, "\n");
         1130  +		fprintf(output, "      -V (or --vhost) instructs filed to prepend all requests with their HTTP\n");
         1131  +		fprintf(output, "                      Host header.\n");
  1078   1132   		fprintf(output, "\n");
  1079   1133   		fprintf(output, "      -b (or --bind) specifies the address to listen for incoming HTTP\n");
  1080   1134   		fprintf(output, "                     requests on.  The default value is \"%s\".\n", BIND_ADDR);
  1081   1135   		fprintf(output, "\n");
  1082   1136   		fprintf(output, "      -p (or --port) specifies the TCP port number to listen for incoming HTTP\n");
  1083   1137   		fprintf(output, "                     requests on.  The default is %u.\n", (unsigned int) PORT);
  1084   1138   		fprintf(output, "\n");
................................................................................
  1222   1276   	close(fd_out);
  1223   1277   
  1224   1278   	return(0);
  1225   1279   }
  1226   1280   
  1227   1281   /* Run process */
  1228   1282   int main(int argc, char **argv) {
  1229         -	struct option options[11];
         1283  +	struct option options[12];
         1284  +	struct filed_options thread_options;
  1230   1285   	const char *bind_addr = BIND_ADDR, *newroot = NULL, *log_file = LOG_FILE;
  1231   1286   	FILE *log_fp;
  1232   1287   	uid_t user = 0;
  1233   1288   	int port = PORT, thread_count = THREAD_COUNT;
  1234   1289   	int cache_size = CACHE_SIZE;
  1235   1290   	int init_ret, chroot_ret, setuid_ret, lookup_ret, chdir_ret;
  1236   1291   	int setuid_enabled = 0, daemon_enabled = 0;
  1237   1292   	int ch;
  1238   1293   	int fd;
  1239   1294   
         1295  +	/* Set default values */
         1296  +	thread_options.vhosts_enabled = 0;
         1297  +
  1240   1298   	/* Process arguments */
  1241   1299   	filed_getopt_long_setopt(&options[0], "port", required_argument, 'p');
  1242   1300   	filed_getopt_long_setopt(&options[1], "threads", required_argument, 't');
  1243   1301   	filed_getopt_long_setopt(&options[2], "cache", required_argument, 'c');
  1244   1302   	filed_getopt_long_setopt(&options[3], "bind", required_argument, 'b');
  1245   1303   	filed_getopt_long_setopt(&options[4], "user", required_argument, 'u');
  1246   1304   	filed_getopt_long_setopt(&options[5], "root", required_argument, 'r');
  1247   1305   	filed_getopt_long_setopt(&options[6], "help", no_argument, 'h');
  1248   1306   	filed_getopt_long_setopt(&options[7], "daemon", no_argument, 'd');
  1249   1307   	filed_getopt_long_setopt(&options[8], "log", required_argument, 'l');
  1250   1308   	filed_getopt_long_setopt(&options[9], "version", no_argument, 'v');
  1251         -	filed_getopt_long_setopt(&options[10], NULL, 0, 0);
  1252         -	while ((ch = getopt_long(argc, argv, "p:t:c:b:u:r:l:hdv", options, NULL)) != -1) {
         1309  +	filed_getopt_long_setopt(&options[10], "vhost", no_argument, 'V');
         1310  +	filed_getopt_long_setopt(&options[11], NULL, 0, 0);
         1311  +	while ((ch = getopt_long(argc, argv, "p:t:c:b:u:r:l:hdvV", options, NULL)) != -1) {
  1253   1312   		switch(ch) {
  1254   1313   			case 'p':
  1255   1314   				port = atoi(optarg);
  1256   1315   				break;
  1257   1316   			case 't':
  1258   1317   				thread_count = atoi(optarg);
  1259   1318   				break;
................................................................................
  1276   1335   				newroot = strdup(optarg);
  1277   1336   				break;
  1278   1337   			case 'l':
  1279   1338   				log_file = strdup(optarg);
  1280   1339   				break;
  1281   1340   			case 'd':
  1282   1341   				daemon_enabled = 1;
         1342  +				break;
         1343  +			case 'V':
         1344  +				thread_options.vhosts_enabled = 1;
         1345  +
  1283   1346   				break;
  1284   1347   			case 'v':
  1285   1348   				printf("filed version %s\n", FILED_VERSION);
  1286   1349   
  1287   1350   				return(0);
  1288   1351   			case '?':
  1289   1352   			case ':':
................................................................................
  1363   1426   	if (init_ret != 0) {
  1364   1427   		perror("filed_logging_thread_init");
  1365   1428   
  1366   1429   		return(4);
  1367   1430   	}
  1368   1431   
  1369   1432   	/* Create worker threads */
  1370         -	init_ret = filed_worker_threads_init(fd, thread_count);
         1433  +	init_ret = filed_worker_threads_init(fd, thread_count, &thread_options);
  1371   1434   	if (init_ret != 0) {
  1372   1435   		perror("filed_worker_threads_init");
  1373   1436   
  1374   1437   		return(5);
  1375   1438   	}
  1376   1439   
  1377   1440   	/* Wait for threads to exit */