Overview
Comment: | Added vhost support |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: | 3298334221905511f3e91d731834f546e9a0c054 |
User & Date: | rkeene on 2014-02-18 03:47:37 |
Other Links: | manifest | tags |
Context
2014-02-18
| ||
05:16 | More logging optimizations check-in: 937df4b0c8 user: rkeene tags: trunk | |
03:47 | Added vhost support check-in: 3298334221 user: rkeene tags: trunk | |
03:45 | Fixed call to wrong function for finding end of HTTP path check-in: 773268af3c user: rkeene tags: trunk | |
Changes
Modified filed.1 from [5b3db65898] to [5afcb460b6].
4 4 filed \- serve files over HTTP 5 5 .SH SYNOPSIS 6 6 .ll +10 7 7 .B filed 8 8 .RB [{ \-h | \-\-help }] 9 9 .RB [{ \-d | \-\-daemon }] 10 10 .RB [{ \-v | \-\-version }] 11 +.RB [{ \-V | \-\-vhost }] 11 12 .RB [{ \-b | \-\-bind } 12 13 .IR address ] 13 14 .RB [{ \-p | \-\-port } 14 15 .IR port ] 15 16 .RB [{ \-t | \-\-threads } 16 17 .IR count ] 17 18 .RB [{ \-c | \-\-cache } ................................................................................ 42 43 43 44 .TP 44 45 .B -v (or --version) 45 46 Instructs 46 47 .B filed 47 48 to print out its version number and then exit. 48 49 50 +.TP 51 +.B -V (or --vhost) 52 +instructs filed to prepend all requests with their HTTP 53 +Host header. 54 + 49 55 .TP 50 56 .B -b (or --bind) 51 57 Specifies the address to listen for incoming HTTP 52 58 requests on. 53 59 54 60 .TP 55 61 .B -p (or --port)
Modified filed.c from [91c2968a74] to [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 */