|  | @@ -466,6 +466,7 @@ struct mg_connection {
 | 
											
												
													
														|  |    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 is already read
 |  |    int64_t consumed_content;   // How many bytes of content is already read
 | 
											
												
													
														|  |    char *buf;                  // Buffer for received data
 |  |    char *buf;                  // Buffer for received data
 | 
											
												
													
														|  | 
 |  | +  char *path_info;            // PATH_INFO part of the URL
 | 
											
												
													
														|  |    int buf_size;               // Buffer size
 |  |    int buf_size;               // Buffer size
 | 
											
												
													
														|  |    int request_len;            // Size of the request + headers in a buffer
 |  |    int request_len;            // Size of the request + headers in a buffer
 | 
											
												
													
														|  |    int data_len;               // Total size of data in a buffer
 |  |    int data_len;               // Total size of data in a buffer
 | 
											
										
											
												
													
														|  | @@ -1556,13 +1557,15 @@ int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name,
 | 
											
												
													
														|  |    return len;
 |  |    return len;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -static void convert_uri_to_file_name(struct mg_connection *conn,
 |  | 
 | 
											
												
													
														|  | -                                     const char *uri, char *buf,
 |  | 
 | 
											
												
													
														|  | -                                     size_t buf_len) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
 | 
											
												
													
														|  | 
 |  | +                                    size_t buf_len, struct mgstat *st) {
 | 
											
												
													
														|  |    struct vec a, b;
 |  |    struct vec a, b;
 | 
											
												
													
														|  | -  const char *rewrite;
 |  | 
 | 
											
												
													
														|  | -  int match_len;
 |  | 
 | 
											
												
													
														|  | 
 |  | +  const char *rewrite, *uri = conn->request_info.uri;
 | 
											
												
													
														|  | 
 |  | +  char *p;
 | 
											
												
													
														|  | 
 |  | +  int match_len, stat_result;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +  buf_len--;  // This is because memmove() for PATH_INFO may shift part
 | 
											
												
													
														|  | 
 |  | +              // of the path one byte on the right.
 | 
											
												
													
														|  |    mg_snprintf(conn, buf, buf_len, "%s%s", conn->ctx->config[DOCUMENT_ROOT],
 |  |    mg_snprintf(conn, buf, buf_len, "%s%s", conn->ctx->config[DOCUMENT_ROOT],
 | 
											
												
													
														|  |                uri);
 |  |                uri);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -1575,10 +1578,32 @@ static void convert_uri_to_file_name(struct mg_connection *conn,
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  #if defined(_WIN32) && !defined(__SYMBIAN32__)
 |  |  #if defined(_WIN32) && !defined(__SYMBIAN32__)
 | 
											
												
													
														|  | -  change_slashes_to_backslashes(buf);
 |  | 
 | 
											
												
													
														|  | 
 |  | +  //change_slashes_to_backslashes(buf);
 | 
											
												
													
														|  |  #endif // _WIN32
 |  |  #endif // _WIN32
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    DEBUG_TRACE(("[%s] -> [%s], [%.*s]", uri, buf, (int) vec.len, vec.ptr));
 |  |    DEBUG_TRACE(("[%s] -> [%s], [%.*s]", uri, buf, (int) vec.len, vec.ptr));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  if ((stat_result = mg_stat(buf, st)) != 0) {
 | 
											
												
													
														|  | 
 |  | +    // Support PATH_INFO for CGI scripts.
 | 
											
												
													
														|  | 
 |  | +    for (p = buf + strlen(buf); p > buf + 1; p--) {
 | 
											
												
													
														|  | 
 |  | +      if (*p == '/') {
 | 
											
												
													
														|  | 
 |  | +        *p = '\0';
 | 
											
												
													
														|  | 
 |  | +        if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
 | 
											
												
													
														|  | 
 |  | +                         strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 &&
 | 
											
												
													
														|  | 
 |  | +            (stat_result = mg_stat(buf, st)) == 0) {
 | 
											
												
													
														|  | 
 |  | +          conn->path_info = p + 1;
 | 
											
												
													
														|  | 
 |  | +          memmove(p + 2, p + 1, strlen(p + 1));
 | 
											
												
													
														|  | 
 |  | +          p[1] = '/';
 | 
											
												
													
														|  | 
 |  | +          break;
 | 
											
												
													
														|  | 
 |  | +        } else {
 | 
											
												
													
														|  | 
 |  | +          *p = '/';
 | 
											
												
													
														|  | 
 |  | +          stat_result = -1;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  return stat_result;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  static int sslize(struct mg_connection *conn, int (*func)(SSL *)) {
 |  |  static int sslize(struct mg_connection *conn, int (*func)(SSL *)) {
 | 
											
										
											
												
													
														|  | @@ -2840,6 +2865,10 @@ static void prepare_cgi_environment(struct mg_connection *conn,
 | 
											
												
													
														|  |    if ((s = getenv("PATH")) != NULL)
 |  |    if ((s = getenv("PATH")) != NULL)
 | 
											
												
													
														|  |      addenv(blk, "PATH=%s", s);
 |  |      addenv(blk, "PATH=%s", s);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +  if (conn->path_info != NULL) {
 | 
											
												
													
														|  | 
 |  | +    addenv(blk, "PATH_INFO=%s", conn->path_info);
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  #if defined(_WIN32)
 |  |  #if defined(_WIN32)
 | 
											
												
													
														|  |    if ((s = getenv("COMSPEC")) != NULL) {
 |  |    if ((s = getenv("COMSPEC")) != NULL) {
 | 
											
												
													
														|  |      addenv(blk, "COMSPEC=%s", s);
 |  |      addenv(blk, "COMSPEC=%s", s);
 | 
											
										
											
												
													
														|  | @@ -3295,7 +3324,7 @@ static void handle_propfind(struct mg_connection *conn, const char* path,
 | 
											
												
													
														|  |  static void handle_request(struct mg_connection *conn) {
 |  |  static void handle_request(struct mg_connection *conn) {
 | 
											
												
													
														|  |    struct mg_request_info *ri = &conn->request_info;
 |  |    struct mg_request_info *ri = &conn->request_info;
 | 
											
												
													
														|  |    char path[PATH_MAX];
 |  |    char path[PATH_MAX];
 | 
											
												
													
														|  | -  int uri_len;
 |  | 
 | 
											
												
													
														|  | 
 |  | +  int stat_result, uri_len;
 | 
											
												
													
														|  |    struct mgstat st;
 |  |    struct mgstat st;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) {
 |  |    if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) {
 | 
											
										
											
												
													
														|  | @@ -3304,7 +3333,7 @@ static void handle_request(struct mg_connection *conn) {
 | 
											
												
													
														|  |    uri_len = strlen(ri->uri);
 |  |    uri_len = strlen(ri->uri);
 | 
											
												
													
														|  |    url_decode(ri->uri, (size_t)uri_len, ri->uri, (size_t)(uri_len + 1), 0);
 |  |    url_decode(ri->uri, (size_t)uri_len, ri->uri, (size_t)(uri_len + 1), 0);
 | 
											
												
													
														|  |    remove_double_dots_and_double_slashes(ri->uri);
 |  |    remove_double_dots_and_double_slashes(ri->uri);
 | 
											
												
													
														|  | -  convert_uri_to_file_name(conn, ri->uri, path, sizeof(path));
 |  | 
 | 
											
												
													
														|  | 
 |  | +  stat_result = convert_uri_to_file_name(conn, path, sizeof(path), &st);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    DEBUG_TRACE(("%s", ri->uri));
 |  |    DEBUG_TRACE(("%s", ri->uri));
 | 
											
												
													
														|  |    if (!check_authorization(conn, path)) {
 |  |    if (!check_authorization(conn, path)) {
 | 
											
										
											
												
													
														|  | @@ -3332,7 +3361,7 @@ static void handle_request(struct mg_connection *conn) {
 | 
											
												
													
														|  |        send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
 |  |        send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
 | 
											
												
													
														|  |                        strerror(ERRNO));
 |  |                        strerror(ERRNO));
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  | -  } else if (mg_stat(path, &st) != 0) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +  } else if (stat_result != 0) {
 | 
											
												
													
														|  |      send_http_error(conn, 404, "Not Found", "%s", "File not found");
 |  |      send_http_error(conn, 404, "Not Found", "%s", "File not found");
 | 
											
												
													
														|  |    } else if (st.is_directory && ri->uri[uri_len - 1] != '/') {
 |  |    } else if (st.is_directory && ri->uri[uri_len - 1] != '/') {
 | 
											
												
													
														|  |      (void) mg_printf(conn,
 |  |      (void) mg_printf(conn,
 | 
											
										
											
												
													
														|  | @@ -3750,7 +3779,8 @@ static void reset_per_request_attributes(struct mg_connection *conn) {
 | 
											
												
													
														|  |    if (ri->remote_user != NULL) {
 |  |    if (ri->remote_user != NULL) {
 | 
											
												
													
														|  |      free((void *) ri->remote_user);
 |  |      free((void *) ri->remote_user);
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  | -  ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
 |  | 
 | 
											
												
													
														|  | 
 |  | +  ri->remote_user = ri->request_method = ri->uri = ri->http_version =
 | 
											
												
													
														|  | 
 |  | +    conn->path_info = NULL;
 | 
											
												
													
														|  |    ri->num_headers = 0;
 |  |    ri->num_headers = 0;
 | 
											
												
													
														|  |    ri->status_code = -1;
 |  |    ri->status_code = -1;
 | 
											
												
													
														|  |  
 |  |  
 |