Check-in [e6e6a5a647]
Overview
Comment:Added redirect support for index pages as well as early-return paths for error pages
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:e6e6a5a6471a0696fecb3d3bdfd0b3e244c24bbc
User & Date: rkeene on 2014-02-18 20:57:48
Other Links: manifest | tags
Context
2014-02-19
16:32
Filed 1.8 check-in: 3e81ad96c8 user: rkeene tags: trunk, 1.8
2014-02-18
20:57
Added redirect support for index pages as well as early-return paths for error pages check-in: e6e6a5a647 user: rkeene tags: trunk
20:03
Removed index.html serving workaround check-in: 6255e77ee6 user: rkeene tags: trunk
Changes

Modified filed.c from [02ed31827c] to [9e958014b2].

    72     72   	enum {
    73     73   		FILED_REQUEST_METHOD_GET,
    74     74   		FILED_REQUEST_METHOD_HEAD
    75     75   	} method;
    76     76   
    77     77   	/*** Path being requested ***/
    78     78   	char path[FILED_PATH_BUFFER_SIZE]; 
           79  +
           80  +	/*** Path type ***/
           81  +	enum {
           82  +		FILED_REQUEST_TYPE_DIRECTORY,
           83  +		FILED_REQUEST_TYPE_OTHER
           84  +	} type;
    79     85   
    80     86   	struct {
    81     87   		struct {
    82     88   			int present;
    83     89   			off_t offset;   /*** Range start ***/
    84     90   			off_t length;   /*** Range length ***/
    85     91   		} range;
................................................................................
   630    636   }
   631    637   
   632    638   /* Process an HTTP request and return the path requested */
   633    639   static struct filed_http_request *filed_get_http_request(FILE *fp, struct filed_http_request *buffer_st, struct filed_options *options) {
   634    640   	char *method, *path;
   635    641   	char *buffer, *workbuffer, *workbuffer_next;
   636    642   	char *fgets_ret;
   637         -	size_t buffer_len;
          643  +	size_t buffer_len, path_len;
   638    644   	off_t range_start, range_end, range_length;
   639    645   	int range_request;
   640    646   	int snprintf_ret;
   641    647   	int i;
   642    648   
   643    649   	/* Set to default values */
   644    650   	range_start = 0;
................................................................................
   684    690   		buffer_st->method = FILED_REQUEST_METHOD_GET;
   685    691   	} else {
   686    692   		/* HEAD request */
   687    693   		buffer_st->method = FILED_REQUEST_METHOD_HEAD;
   688    694   	}
   689    695   
   690    696   	/* Note path */
   691         -	strcpy(buffer_st->path, path);
          697  +	path_len = strlen(path);
          698  +	memcpy(buffer_st->path, path, path_len + 1);
          699  +
          700  +	/* Determine type of request from path */
          701  +	if (path_len == 0) {
          702  +		buffer_st->type = FILED_REQUEST_TYPE_DIRECTORY;
          703  +	} else {
          704  +		if (path[path_len - 1] == '/') {
          705  +			buffer_st->type = FILED_REQUEST_TYPE_DIRECTORY;
          706  +		} else {
          707  +			buffer_st->type = FILED_REQUEST_TYPE_OTHER;
          708  +		}
          709  +	}
   692    710   
   693    711   	/* Reset buffer for later use */
   694    712   	buffer = buffer_st->tmpbuf;
   695    713   
   696    714   	for (i = 0; i < 100; i++) {
   697    715   		fgets_ret = fgets(buffer, buffer_len, fp);
   698    716   		if (fgets_ret == NULL) {
................................................................................
   779    797   		}
   780    798   	}
   781    799   
   782    800   	return(buffer_st);
   783    801   }
   784    802   
   785    803   /* Return an error page */
   786         -static void filed_error_page(FILE *fp, const char *date_current, int error_number, int method) {
          804  +static void filed_error_page(FILE *fp, const char *date_current, int error_number, int method, const char *reason, struct filed_log_entry *log) {
   787    805   	char *error_string = "<html><head><title>ERROR</title></head><body>Unable to process request</body></html>";
   788    806   
   789    807   	fprintf(fp, "HTTP/1.1 %i Not OK\r\nDate: %s\r\nServer: filed\r\nLast-Modified: %s\r\nContent-Length: %llu\r\nContent-Type: %s\r\nConnection: close\r\n\r\n",
   790    808   		error_number,
   791    809   		date_current,
   792    810   		date_current,
   793    811   		(unsigned long long) strlen(error_string),
................................................................................
   795    813   	);
   796    814   
   797    815   	/* silence error string for HEAD requests */
   798    816   	if (method != FILED_REQUEST_METHOD_HEAD) {
   799    817   		fprintf(fp, "%s", error_string);
   800    818   	}
   801    819   
          820  +	/* Log error */
          821  +	/** reason must point to a globally allocated value **/
          822  +	log->reason = reason;
          823  +	log->http_code = error_number;
          824  +
          825  +	filed_log_entry(log);
          826  +
          827  +	/* Close connection */
          828  +	fclose(fp);
          829  +
          830  +	return;
          831  +}
          832  +
          833  +/* Return a redirect to index.html */
          834  +static void filed_redirect_index(FILE *fp, const char *date_current, const char *path, struct filed_log_entry *log) {
          835  +	int http_code = 301;
          836  +	fprintf(fp, "HTTP/1.1 %i OK\r\nDate: %s\r\nServer: filed\r\nLast-Modified: %s\r\nContent-Length: 0\r\nConnection: close\r\nLocation: %s\r\n\r\n",
          837  +		http_code,
          838  +		date_current,
          839  +		date_current,
          840  +		"index.html"
          841  +	);
          842  +
          843  +	/* Log redirect */
          844  +	log->reason = "redirect";
          845  +	log->http_code = http_code;
          846  +
          847  +	filed_log_entry(log);
          848  +
          849  +	/* Close connection */
          850  +	fclose(fp);
          851  +
   802    852   	return;
          853  +
          854  +	/* Currently unused: path */
          855  +	path = path;
   803    856   }
   804    857   
   805    858   /* Handle a single request from a client */
   806    859   static void filed_handle_client(int fd, struct filed_http_request *request, struct filed_log_entry *log, struct filed_options *options) {
   807    860   	struct filed_fileinfo *fileinfo;
   808    861   	ssize_t sendfile_ret;
   809    862   	size_t sendfile_size;
................................................................................
   829    882   
   830    883   		return;
   831    884   	}
   832    885   
   833    886   	request = filed_get_http_request(fp, request, options);
   834    887   
   835    888   	if (request == NULL) {
   836         -		filed_error_page(fp, date_current, 500, FILED_REQUEST_METHOD_GET);
   837         -
   838    889   		log->buffer[0] = '\0';
   839         -		log->http_code = 500;
   840         -		log->reason = "format";
   841    890   
   842         -		filed_log_entry(log);
   843         -
   844         -		fclose(fp);
          891  +		filed_error_page(fp, date_current, 500, FILED_REQUEST_METHOD_GET, "format", log);
   845    892   
   846    893   		return;
   847    894   	}
   848    895   
   849    896   	path = request->path;
   850    897   	strcpy(log->buffer, path);
   851    898   	log->method = request->method;
   852    899   
   853         -	http_code = -1;
          900  +	/* If the requested path is a directory, redirect to index page */
          901  +	if (request->type == FILED_REQUEST_TYPE_DIRECTORY) {
          902  +		filed_redirect_index(fp, date_current, path, log);
          903  +
          904  +		return;
          905  +	}
   854    906   
   855    907   	fileinfo = filed_open_file(path, &request->fileinfo);
   856    908   	if (fileinfo == NULL) {
   857         -		filed_error_page(fp, date_current, 404, request->method);
          909  +		filed_error_page(fp, date_current, 404, request->method, "open_failed", log);
   858    910   
   859         -		log->http_code = 404;
   860         -		log->reason = "open_failed";
          911  +		return;
          912  +	}
   861    913   
   862         -		filed_log_entry(log);
   863         -	} else {
          914  +	if (request->headers.range.present) {
   864    915   		if (request->headers.range.offset != 0 || request->headers.range.length >= 0) {
   865    916   			if (request->headers.range.offset >= fileinfo->len) {
   866         -				filed_error_page(fp, date_current, 416, request->method);
          917  +				filed_error_page(fp, date_current, 416, request->method, "range_invalid", log);
   867    918   
   868         -				log->http_code = 416;
   869         -				log->reason = "range_invalid";
          919  +				close(fileinfo->fd);
   870    920   
   871         -				filed_log_entry(log);
   872         -			} else {
   873         -				if (request->headers.range.length == ((off_t) -1)) {
   874         -					filed_log_msg_debug("Computing length to fit in bounds: fileinfo->len = %llu, request->headers.range.offset = %llu",
   875         -						(unsigned long long) fileinfo->len,
   876         -						(unsigned long long) request->headers.range.offset
   877         -					);
          921  +				return;
          922  +			}
   878    923   
   879         -					request->headers.range.length = fileinfo->len - request->headers.range.offset;
   880         -				}
   881         -
   882         -				filed_log_msg_debug("Partial request, starting at: %llu and running for %lli bytes",
   883         -					(unsigned long long) request->headers.range.offset,
   884         -					(long long) request->headers.range.length
          924  +			if (request->headers.range.length == ((off_t) -1)) {
          925  +				filed_log_msg_debug("Computing length to fit in bounds: fileinfo->len = %llu, request->headers.range.offset = %llu",
          926  +					(unsigned long long) fileinfo->len,
          927  +					(unsigned long long) request->headers.range.offset
   885    928   				);
   886    929   
   887         -				http_code = 206;
          930  +				request->headers.range.length = fileinfo->len - request->headers.range.offset;
   888    931   			}
   889         -		} else {
   890         -			if (request->headers.range.present) {
   891         -				http_code = 206;
   892         -			} else {
   893         -				http_code = 200;
   894         -			}
   895         -			request->headers.range.offset = 0;
   896         -			request->headers.range.length = fileinfo->len;
   897         -		}
   898    932   
   899         -		if (http_code > 0) {
   900         -			fprintf(fp, "HTTP/1.1 %i OK\r\nDate: %s\r\nServer: filed\r\nLast-Modified: %s\r\nContent-Length: %llu\r\nAccept-Ranges: bytes\r\nContent-Type: %s\r\nConnection: close\r\nETag: \"%s\"\r\n",
   901         -				http_code,
   902         -				date_current,
   903         -				fileinfo->lastmod,
   904         -				(unsigned long long) request->headers.range.length,
   905         -				fileinfo->type,
   906         -				fileinfo->etag
          933  +			filed_log_msg_debug("Partial request, starting at: %llu and running for %lli bytes",
          934  +				(unsigned long long) request->headers.range.offset,
          935  +				(long long) request->headers.range.length
   907    936   			);
   908         -			if (http_code == 206) {
   909         -				fprintf(fp, "Content-Range: bytes %llu-%llu/%llu\r\n",
   910         -					(unsigned long long) request->headers.range.offset,
   911         -					(unsigned long long) (request->headers.range.offset + request->headers.range.length - 1),
   912         -					(unsigned long long) fileinfo->len
   913         -				);
   914         -			}
   915         -			fprintf(fp, "\r\n");
   916         -			fflush(fp);
   917         -
   918         -			log->http_code = http_code;
   919         -			log->reason = "OK";
   920         -			log->starttime = time(NULL);
   921         -			log->req_offset = request->headers.range.offset;
   922         -			log->req_length = request->headers.range.length;
   923         -			log->file_length = fileinfo->len;
          937  +
          938  +		}
          939  +
          940  +		http_code = 206;
          941  +	} else {
          942  +		http_code = 200;
          943  +
          944  +		/* Compute fake range parameters that includes the entire file */
          945  +		request->headers.range.offset = 0;
          946  +		request->headers.range.length = fileinfo->len;
          947  +	}
          948  +
          949  +	fprintf(fp, "HTTP/1.1 %i OK\r\nDate: %s\r\nServer: filed\r\nLast-Modified: %s\r\nContent-Length: %llu\r\nAccept-Ranges: bytes\r\nContent-Type: %s\r\nConnection: close\r\nETag: \"%s\"\r\n",
          950  +		http_code,
          951  +		date_current,
          952  +		fileinfo->lastmod,
          953  +		(unsigned long long) request->headers.range.length,
          954  +		fileinfo->type,
          955  +		fileinfo->etag
          956  +	);
          957  +
          958  +	if (http_code == 206) {
          959  +		fprintf(fp, "Content-Range: bytes %llu-%llu/%llu\r\n",
          960  +			(unsigned long long) request->headers.range.offset,
          961  +			(unsigned long long) (request->headers.range.offset + request->headers.range.length - 1),
          962  +			(unsigned long long) fileinfo->len
          963  +		);
          964  +	}
          965  +	fprintf(fp, "\r\n");
          966  +	fflush(fp);
          967  +
          968  +	log->http_code = http_code;
          969  +	log->reason = "OK";
          970  +	log->starttime = time(NULL);
          971  +	log->req_offset = request->headers.range.offset;
          972  +	log->req_length = request->headers.range.length;
          973  +	log->file_length = fileinfo->len;
   924    974   
   925    975   #ifdef FILED_NONBLOCK_HTTP
   926         -			int socket_flags;
   927         -			fd_set rfd, wfd;
   928         -			char sinkbuf[8192];
   929         -			ssize_t read_ret;
          976  +	int socket_flags;
          977  +	fd_set rfd, wfd;
          978  +	char sinkbuf[8192];
          979  +	ssize_t read_ret;
   930    980   
   931         -			FD_ZERO(&rfd);
   932         -			FD_ZERO(&wfd);
   933         -			FD_SET(fd, &rfd);
   934         -			FD_SET(fd, &wfd);
          981  +	FD_ZERO(&rfd);
          982  +	FD_ZERO(&wfd);
          983  +	FD_SET(fd, &rfd);
          984  +	FD_SET(fd, &wfd);
   935    985   
   936         -			socket_flags = fcntl(fd, F_GETFL);
   937         -			fcntl(fd, F_SETFL, socket_flags | O_NONBLOCK);
          986  +	socket_flags = fcntl(fd, F_GETFL);
          987  +	fcntl(fd, F_SETFL, socket_flags | O_NONBLOCK);
   938    988   #endif
          989  +	sendfile_offset = request->headers.range.offset;
          990  +	sendfile_len = request->headers.range.length;
          991  +	sendfile_sent = 0;
          992  +	while (request->method == FILED_REQUEST_METHOD_GET) {
          993  +		if (sendfile_len > FILED_SENDFILE_MAX) {
          994  +			sendfile_size = FILED_SENDFILE_MAX;
          995  +		} else {
          996  +			sendfile_size = sendfile_len;
          997  +		}
   939    998   
   940         -			sendfile_offset = request->headers.range.offset;
   941         -			sendfile_len = request->headers.range.length;
   942         -			sendfile_sent = 0;
   943         -			while (request->method == FILED_REQUEST_METHOD_GET) {
   944         -				if (sendfile_len > FILED_SENDFILE_MAX) {
   945         -					sendfile_size = FILED_SENDFILE_MAX;
   946         -				} else {
   947         -					sendfile_size = sendfile_len;
   948         -				}
   949         -
   950         -				sendfile_ret = sendfile(fd, fileinfo->fd, &sendfile_offset, sendfile_size);
   951         -				if (sendfile_ret <= 0) {
          999  +		sendfile_ret = sendfile(fd, fileinfo->fd, &sendfile_offset, sendfile_size);
         1000  +		if (sendfile_ret <= 0) {
   952   1001   #ifdef FILED_NONBLOCK_HTTP
   953         -					if (errno == EAGAIN) {
   954         -						sendfile_ret = 0;
         1002  +			if (errno == EAGAIN) {
         1003  +				sendfile_ret = 0;
   955   1004   
   956         -						while (1) {
   957         -							select(fd + 1, &rfd, &wfd, NULL, NULL);
   958         -							if (FD_ISSET(fd, &rfd)) {
   959         -								read_ret = read(fd, sinkbuf, sizeof(sinkbuf));
   960         -
   961         -								if (read_ret <= 0) {
   962         -									break;
   963         -								}
   964         -							}
   965         -
   966         -							if (FD_ISSET(fd, &wfd)) {
   967         -								read_ret = 1;
   968         -
   969         -								break;
   970         -							}
   971         -						}
         1005  +				while (1) {
         1006  +					select(fd + 1, &rfd, &wfd, NULL, NULL);
         1007  +					if (FD_ISSET(fd, &rfd)) {
         1008  +						read_ret = read(fd, sinkbuf, sizeof(sinkbuf));
   972   1009   
   973   1010   						if (read_ret <= 0) {
   974   1011   							break;
   975   1012   						}
   976         -					} else {
         1013  +					}
         1014  +
         1015  +					if (FD_ISSET(fd, &wfd)) {
         1016  +						read_ret = 1;
         1017  +
   977   1018   						break;
   978   1019   					}
   979         -#else
   980         -					break;
   981         -#endif
   982   1020   				}
   983   1021   
   984         -				sendfile_len -= sendfile_ret;
   985         -				sendfile_sent += sendfile_ret;
   986         -				if (sendfile_len == 0) {
         1022  +				if (read_ret <= 0) {
   987   1023   					break;
   988   1024   				}
         1025  +			} else {
         1026  +				break;
   989   1027   			}
         1028  +#else
         1029  +			break;
         1030  +#endif
         1031  +		}
   990   1032   
   991         -			log->endtime = (time_t) -1;
   992         -			log->sent_length = sendfile_sent;
   993         -
   994         -			filed_log_entry(log);
         1033  +		sendfile_len -= sendfile_ret;
         1034  +		sendfile_sent += sendfile_ret;
         1035  +		if (sendfile_len == 0) {
         1036  +			break;
   995   1037   		}
         1038  +	}
   996   1039   
   997         -		close(fileinfo->fd);
   998         -	}
         1040  +	log->endtime = (time_t) -1;
         1041  +	log->sent_length = sendfile_sent;
         1042  +
         1043  +	filed_log_entry(log);
         1044  +
         1045  +	close(fileinfo->fd);
   999   1046   
  1000   1047   	fclose(fp);
  1001   1048   
  1002   1049   	return;
  1003   1050   }
  1004   1051   
  1005   1052   /* Handle incoming connections */