|  | @@ -826,8 +826,8 @@ struct mg_connection {
 | 
											
												
													
														|  |      SSL *ssl;                       /* SSL descriptor */
 |  |      SSL *ssl;                       /* SSL descriptor */
 | 
											
												
													
														|  |      SSL_CTX *client_ssl_ctx;        /* SSL context for client connections */
 |  |      SSL_CTX *client_ssl_ctx;        /* SSL context for client connections */
 | 
											
												
													
														|  |      struct socket client;           /* Connected client */
 |  |      struct socket client;           /* Connected client */
 | 
											
												
													
														|  | -    time_t birth_time;              /* Time (wall clock) when connection was established */
 |  | 
 | 
											
												
													
														|  | -    struct timespec req_begin;      /* Time (since system start) when the request was received */
 |  | 
 | 
											
												
													
														|  | 
 |  | +    time_t conn_birth_time;         /* Time (wall clock) when connection was established */
 | 
											
												
													
														|  | 
 |  | +    struct timespec req_time;       /* Time (since system start) when the request was received */
 | 
											
												
													
														|  |      int64_t num_bytes_sent;         /* Total bytes sent to client */
 |  |      int64_t num_bytes_sent;         /* Total bytes sent to client */
 | 
											
												
													
														|  |      int64_t content_len;            /* Content-Length header value */
 |  |      int64_t content_len;            /* Content-Length header value */
 | 
											
												
													
														|  |      int64_t consumed_content;       /* How many bytes of content have been read */
 |  |      int64_t consumed_content;       /* How many bytes of content have been read */
 | 
											
										
											
												
													
														|  | @@ -2447,20 +2447,40 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t le
 | 
											
												
													
														|  |  static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len)
 |  |  static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  |      int nread;
 |  |      int nread;
 | 
											
												
													
														|  | 
 |  | +    double timeout = -1;
 | 
											
												
													
														|  | 
 |  | +    struct timespec start, now;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    if (fp != NULL) {
 |  | 
 | 
											
												
													
														|  | -        /* Use read() instead of fread(), because if we're reading from the
 |  | 
 | 
											
												
													
														|  | -           CGI pipe, fread() may block until IO buffer is filled up. We cannot
 |  | 
 | 
											
												
													
														|  | -           afford to block and must pass all read bytes immediately to the
 |  | 
 | 
											
												
													
														|  | -           client. */
 |  | 
 | 
											
												
													
														|  | -        nread = read(fileno(fp), buf, (size_t) len);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    if (conn->ctx->config[REQUEST_TIMEOUT]) {
 | 
											
												
													
														|  | 
 |  | +        timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    if (timeout>0) {
 | 
											
												
													
														|  | 
 |  | +        clock_gettime(CLOCK_MONOTONIC, &start);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    do {
 | 
											
												
													
														|  | 
 |  | +        if (fp != NULL) {
 | 
											
												
													
														|  | 
 |  | +            /* Use read() instead of fread(), because if we're reading from the
 | 
											
												
													
														|  | 
 |  | +            CGI pipe, fread() may block until IO buffer is filled up. We cannot
 | 
											
												
													
														|  | 
 |  | +            afford to block and must pass all read bytes immediately to the
 | 
											
												
													
														|  | 
 |  | +            client. */
 | 
											
												
													
														|  | 
 |  | +            nread = read(fileno(fp), buf, (size_t) len);
 | 
											
												
													
														|  |  #ifndef NO_SSL
 |  |  #ifndef NO_SSL
 | 
											
												
													
														|  | -    } else if (conn->ssl != NULL) {
 |  | 
 | 
											
												
													
														|  | -        nread = SSL_read(conn->ssl, buf, len);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        } else if (conn->ssl != NULL) {
 | 
											
												
													
														|  | 
 |  | +            nread = SSL_read(conn->ssl, buf, len);
 | 
											
												
													
														|  |  #endif
 |  |  #endif
 | 
											
												
													
														|  | -    } else {
 |  | 
 | 
											
												
													
														|  | -        nread = recv(conn->client.sock, buf, (size_t) len, 0);
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | 
 |  | +        } else {
 | 
											
												
													
														|  | 
 |  | +            nread = recv(conn->client.sock, buf, (size_t) len, 0);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        if (conn->ctx->stop_flag) {
 | 
											
												
													
														|  | 
 |  | +            return -1;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        if (nread >= 0) {
 | 
											
												
													
														|  | 
 |  | +            return nread;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        if (timeout>0) {
 | 
											
												
													
														|  | 
 |  | +            clock_gettime(CLOCK_MONOTONIC, &now);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +    } while ((timeout<=0) || (difftime(now.tv_sec,start.tv_sec)<=timeout));
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      return conn->ctx->stop_flag ? -1 : nread;
 |  |      return conn->ctx->stop_flag ? -1 : nread;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
										
											
												
													
														|  | @@ -4314,7 +4334,7 @@ static int read_request(FILE *fp, struct mg_connection *conn,
 | 
											
												
													
														|  |      while ((conn->ctx->stop_flag == 0) &&
 |  |      while ((conn->ctx->stop_flag == 0) &&
 | 
											
												
													
														|  |             (*nread < bufsiz) &&
 |  |             (*nread < bufsiz) &&
 | 
											
												
													
														|  |             (request_len == 0) &&
 |  |             (request_len == 0) &&
 | 
											
												
													
														|  | -           ((difftime(last_action_time.tv_sec, conn->birth_time) <= request_timout) || (request_timout < 0)) &&
 |  | 
 | 
											
												
													
														|  | 
 |  | +           ((difftime(last_action_time.tv_sec, conn->req_time.tv_sec) <= request_timout) || (request_timout < 0)) &&
 | 
											
												
													
														|  |             ((n = pull(fp, conn, buf + *nread, bufsiz - *nread)) > 0)
 |  |             ((n = pull(fp, conn, buf + *nread, bufsiz - *nread)) > 0)
 | 
											
												
													
														|  |            ) {
 |  |            ) {
 | 
											
												
													
														|  |          *nread += n;
 |  |          *nread += n;
 | 
											
										
											
												
													
														|  | @@ -6624,7 +6644,7 @@ static void log_access(const struct mg_connection *conn)
 | 
											
												
													
														|  |      if (fp == NULL && conn->ctx->callbacks.log_message == NULL)
 |  |      if (fp == NULL && conn->ctx->callbacks.log_message == NULL)
 | 
											
												
													
														|  |          return;
 |  |          return;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    tm = localtime(&conn->birth_time);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    tm = localtime(&conn->conn_birth_time);
 | 
											
												
													
														|  |      if (tm != NULL) {
 |  |      if (tm != NULL) {
 | 
											
												
													
														|  |          strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", tm);
 |  |          strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", tm);
 | 
											
												
													
														|  |      } else {
 |  |      } else {
 | 
											
										
											
												
													
														|  | @@ -7178,8 +7198,8 @@ static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *
 | 
											
												
													
														|  |              conn->content_len = 0;
 |  |              conn->content_len = 0;
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -        /* Here we do not set the socket_birth time but the request begin */
 |  | 
 | 
											
												
													
														|  | -        clock_gettime(CLOCK_MONOTONIC, &(conn->req_begin));
 |  | 
 | 
											
												
													
														|  | 
 |  | +        /* Set the time the request was received. This value should be used for timeouts. */
 | 
											
												
													
														|  | 
 |  | +        clock_gettime(CLOCK_MONOTONIC, &(conn->req_time));
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      return 1;
 |  |      return 1;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
										
											
												
													
														|  | @@ -7471,7 +7491,7 @@ static void *worker_thread_run(void *thread_func_param)
 | 
											
												
													
														|  |             signal sq_empty condvar to wake up the master waiting in
 |  |             signal sq_empty condvar to wake up the master waiting in
 | 
											
												
													
														|  |             produce_socket() */
 |  |             produce_socket() */
 | 
											
												
													
														|  |          while (consume_socket(ctx, &conn->client)) {
 |  |          while (consume_socket(ctx, &conn->client)) {
 | 
											
												
													
														|  | -            conn->birth_time = time(NULL);
 |  | 
 | 
											
												
													
														|  | 
 |  | +            conn->conn_birth_time = time(NULL);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |              /* Fill in IP, port info early so even if SSL setup below fails,
 |  |              /* Fill in IP, port info early so even if SSL setup below fails,
 | 
											
												
													
														|  |                 error handler would have the corresponding info.
 |  |                 error handler would have the corresponding info.
 | 
											
										
											
												
													
														|  | @@ -7600,7 +7620,7 @@ static void accept_new_connection(const struct socket *listener,
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          /* Set socket timeout to the given value, but not more than 10 seconds,
 |  |          /* Set socket timeout to the given value, but not more than 10 seconds,
 | 
											
												
													
														|  |             so the server can exit after 10 seconds if required. */
 |  |             so the server can exit after 10 seconds if required. */
 | 
											
												
													
														|  | -        /* TODO: Currently values > 10 s are round up to the next 10 s. 
 |  | 
 | 
											
												
													
														|  | 
 |  | +        /* TODO: Currently values > 10 s are round up to the next 10 s.
 | 
											
												
													
														|  |                   For values like 24 s a socket timeout of 8 or 12 s would be better. */
 |  |                   For values like 24 s a socket timeout of 8 or 12 s would be better. */
 | 
											
												
													
														|  |          if ((timeout>0) && (timeout<10000)) {
 |  |          if ((timeout>0) && (timeout<10000)) {
 | 
											
												
													
														|  |              set_sock_timeout(so.sock, timeout);
 |  |              set_sock_timeout(so.sock, timeout);
 |