Check-in [b4fa45b6aa]
Overview
Comment:Updated to support HTTP Connection Keep-Alive
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:b4fa45b6aa3bc1a7390f3ae961a921edd1f1be86
User & Date: rkeene on 2014-10-13 08:04:09
Other Links: manifest | tags
References
2014-10-13
14:59
Fixed file descriptor leaking introduced in [b4fa45b6aa] and made connection re-use more clean check-in: 679bcc1373 user: rkeene tags: trunk
Context
2014-10-13
08:12
Filed 1.10 check-in: dd8a7297f3 user: rkeene tags: trunk, 1.10
08:04
Updated to support HTTP Connection Keep-Alive check-in: b4fa45b6aa user: rkeene tags: trunk
2014-08-31
18:07
Updated to use a fallback mime.types file if specified one is unavailable check-in: 862bf6f56b user: rkeene tags: trunk
Changes

Modified filed.c from [9ca8af3757] to [d1e3cfdb7f].

    90     90   			off_t length;   /*** Range length ***/
    91     91   		} range;
    92     92   
    93     93   		struct {
    94     94   			int present;
    95     95   			char host[FILED_PATH_BUFFER_SIZE];
    96     96   		} host;
           97  +
           98  +		enum {
           99  +			FILED_CONNECTION_CLOSE,
          100  +			FILED_CONNECTION_KEEP_ALIVE
          101  +		} connection;
    97    102   	} headers;
    98    103   };
    99    104   
   100    105   /* Log record */
   101    106   struct filed_log_entry {
   102    107   	/* Type of log entry */
   103    108   	enum {
................................................................................
   685    690   
   686    691   	/* Set to default values */
   687    692   	range_start = 0;
   688    693   	range_end   = 0;
   689    694   	range_request = 0;
   690    695   	range_length = -1;
   691    696   	buffer_st->headers.host.present = 0;
          697  +	buffer_st->headers.connection = FILED_CONNECTION_CLOSE;
   692    698   
   693    699   	buffer = buffer_st->tmpbuf;
   694    700   	buffer_len = sizeof(buffer_st->tmpbuf);
   695    701   
   696    702   	fgets_ret = fgets(buffer, buffer_len, fp);
   697    703   	if (fgets_ret == NULL) {
   698    704   		return(NULL);
................................................................................
   784    790   
   785    791   			workbuffer = buffer + 5;
   786    792   			while (*workbuffer == ' ') {
   787    793   				workbuffer++;
   788    794   			}
   789    795   
   790    796   			strcpy(buffer_st->headers.host.host, workbuffer);
          797  +		} else if (strncasecmp(buffer, "Connection: Keep-Alive", 22) == 0) {
          798  +			buffer_st->headers.connection = FILED_CONNECTION_KEEP_ALIVE;
   791    799   		}
   792    800   
   793    801   		if (memcmp(buffer, "\r\n", 2) == 0) {
   794    802   			break;
   795    803   		}
   796    804   	}
   797    805   
................................................................................
   887    895   	fclose(fp);
   888    896   
   889    897   	return;
   890    898   
   891    899   	/* Currently unused: path */
   892    900   	path = path;
   893    901   }
          902  +
          903  +/* Convert an enum representing the "Connection" header value to a string */
          904  +static const char *filed_connection_str(int connection_value) {
          905  +	switch (connection_value) {
          906  +		case FILED_CONNECTION_CLOSE:
          907  +			return("close");
          908  +		case FILED_CONNECTION_KEEP_ALIVE:
          909  +			return("keep-alive");
          910  +	}
          911  +
          912  +	return("close");
          913  +}
   894    914   
   895    915   /* Handle a single request from a client */
   896         -static void filed_handle_client(int fd, struct filed_http_request *request, struct filed_log_entry *log, struct filed_options *options) {
          916  +static int filed_handle_client(int fd, struct filed_http_request *request, struct filed_log_entry *log, struct filed_options *options) {
   897    917   	struct filed_fileinfo *fileinfo;
   898    918   	ssize_t sendfile_ret;
   899    919   	size_t sendfile_size;
   900    920   	off_t sendfile_offset, sendfile_sent, sendfile_len;
   901    921   	char *path;
   902    922   	char *date_current, date_current_b[64];
   903    923   	int http_code;
................................................................................
   913    933   
   914    934   		log->buffer[0] = '\0';
   915    935   		log->http_code = -1;
   916    936   		log->reason = "fdopen_failed";
   917    937   
   918    938   		filed_log_entry(log);
   919    939   
   920         -		return;
          940  +		return(0);
   921    941   	}
   922    942   
   923    943   	request = filed_get_http_request(fp, request, options);
   924    944   
   925    945   	if (request == NULL) {
   926    946   		log->buffer[0] = '\0';
   927    947   
   928    948   		filed_error_page(fp, date_current, 500, FILED_REQUEST_METHOD_GET, "format", log);
   929    949   
   930         -		return;
          950  +		return(0);
   931    951   	}
   932    952   
   933    953   	path = request->path;
   934    954   	strcpy(log->buffer, path);
   935    955   	log->method = request->method;
   936    956   
   937    957   	/* If the requested path is a directory, redirect to index page */
   938    958   	if (request->type == FILED_REQUEST_TYPE_DIRECTORY) {
   939    959   		filed_redirect_index(fp, date_current, path, log);
   940    960   
   941         -		return;
          961  +		return(0);
   942    962   	}
   943    963   
   944    964   	fileinfo = filed_open_file(path, &request->fileinfo);
   945    965   	if (fileinfo == NULL) {
   946    966   		filed_error_page(fp, date_current, 404, request->method, "open_failed", log);
   947    967   
   948         -		return;
          968  +		return(0);
   949    969   	}
   950    970   
   951    971   	if (request->headers.range.present) {
   952    972   		if (request->headers.range.offset != 0 || request->headers.range.length >= 0) {
   953    973   			if (request->headers.range.offset >= fileinfo->len) {
   954    974   				filed_error_page(fp, date_current, 416, request->method, "range_invalid", log);
   955    975   
   956    976   				close(fileinfo->fd);
   957    977   
   958         -				return;
          978  +				return(0);
   959    979   			}
   960    980   
   961    981   			if (request->headers.range.length == ((off_t) -1)) {
   962    982   				filed_log_msg_debug("Computing length to fit in bounds: fileinfo->len = %llu, request->headers.range.offset = %llu",
   963    983   					(unsigned long long) fileinfo->len,
   964    984   					(unsigned long long) request->headers.range.offset
   965    985   				);
................................................................................
   979    999   		http_code = 200;
   980   1000   
   981   1001   		/* Compute fake range parameters that includes the entire file */
   982   1002   		request->headers.range.offset = 0;
   983   1003   		request->headers.range.length = fileinfo->len;
   984   1004   	}
   985   1005   
   986         -	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",
         1006  +	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: %s\r\nETag: \"%s\"\r\n",
   987   1007   		http_code,
   988   1008   		date_current,
   989   1009   		fileinfo->lastmod,
   990   1010   		(unsigned long long) request->headers.range.length,
   991   1011   		fileinfo->type,
         1012  +		filed_connection_str(request->headers.connection),
   992   1013   		fileinfo->etag
   993   1014   	);
   994   1015   
   995   1016   	if (http_code == 206) {
   996   1017   		fprintf(fp, "Content-Range: bytes %llu-%llu/%llu\r\n",
   997   1018   			(unsigned long long) request->headers.range.offset,
   998   1019   			(unsigned long long) (request->headers.range.offset + request->headers.range.length - 1),
................................................................................
  1075   1096   	}
  1076   1097   
  1077   1098   	log->endtime = (time_t) -1;
  1078   1099   	log->sent_length = sendfile_sent;
  1079   1100   
  1080   1101   	filed_log_entry(log);
  1081   1102   
  1082         -	close(fileinfo->fd);
         1103  +	if (request->headers.connection != FILED_CONNECTION_KEEP_ALIVE) {
         1104  +		close(fileinfo->fd);
  1083   1105   
  1084         -	fclose(fp);
         1106  +		fclose(fp);
  1085   1107   
  1086         -	return;
         1108  +		return(0);
         1109  +	}
         1110  +
         1111  +	return(1);
  1087   1112   }
  1088   1113   
  1089   1114   /* Handle incoming connections */
  1090   1115   static void *filed_worker_thread(void *arg_v) {
  1091   1116   	struct filed_worker_thread_args *arg;
  1092   1117   	struct filed_http_request request;
  1093   1118   	struct filed_log_entry *log, local_dummy_log;
  1094   1119   	struct filed_options *options;
  1095   1120   	struct sockaddr_in6 addr;
  1096   1121   	socklen_t addrlen;
  1097   1122   	int failure_count = 0, max_failure_count = FILED_MAX_FAILURE_COUNT;
  1098         -	int master_fd, fd;
         1123  +	int accept_new = 1;
         1124  +	int master_fd, fd = -1;
  1099   1125   
  1100   1126   	/* Read arguments */
  1101   1127   	arg = arg_v;
  1102   1128   
  1103   1129   	master_fd = arg->fd;
  1104   1130   	options = &arg->options;
  1105   1131   
................................................................................
  1116   1142   
  1117   1143   			break;
  1118   1144   		}
  1119   1145   
  1120   1146   		log->type = FILED_LOG_TYPE_TRANSFER;
  1121   1147   
  1122   1148   		/* Accept a new client */
  1123         -		addrlen = sizeof(addr);
  1124         -		fd = accept(master_fd, (struct sockaddr *) &addr, &addrlen);
         1149  +		if (accept_new) {
         1150  +			addrlen = sizeof(addr);
         1151  +			fd = accept(master_fd, (struct sockaddr *) &addr, &addrlen);
         1152  +		}
  1125   1153   
  1126   1154   		/*
  1127   1155   		 * If we fail, make a note of it so we don't go into a loop of
  1128   1156   		 * accept() failing
  1129   1157   		 */
  1130   1158   		if (fd < 0) {
  1131   1159   			/* Log the new connection */
................................................................................
  1146   1174   			log->port = addr.sin6_port;
  1147   1175   		}
  1148   1176   
  1149   1177   		/* Reset failure count*/
  1150   1178   		failure_count = 0;
  1151   1179   
  1152   1180   		/* Handle socket */
  1153         -		filed_handle_client(fd, &request, log, options);
         1181  +		accept_new = !filed_handle_client(fd, &request, log, options);
  1154   1182   	}
  1155   1183   
  1156   1184   	/* Report error */
  1157   1185   	filed_log_msg("THREAD_DIED ABNORMAL");
  1158   1186   
  1159   1187   	return(NULL);
  1160   1188