Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check that file exists #1054

Merged
merged 1 commit into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.openvsx.cache.CacheService;
import org.eclipse.openvsx.entities.Extension;
import org.eclipse.openvsx.entities.ExtensionVersion;
import org.eclipse.openvsx.entities.FileResource;
Expand All @@ -19,6 +20,8 @@
import org.eclipse.openvsx.search.SearchUtilService;
import org.eclipse.openvsx.storage.StorageUtilService;
import org.eclipse.openvsx.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -28,6 +31,8 @@

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;

Expand All @@ -41,13 +46,15 @@

@Component
public class LocalVSCodeService implements IVSCodeService {
protected final Logger logger = LoggerFactory.getLogger(LocalVSCodeService.class);

private final RepositoryService repositories;
private final VersionService versions;
private final SearchUtilService search;
private final StorageUtilService storageUtil;
private final ExtensionVersionIntegrityService integrityService;
private final WebResourceService webResources;
private final CacheService cache;

private final StreamingResponseBody builtinExtensionResponse = outputStream -> {
var message = "Built-in extension namespace '" + BuiltInExtensionUtil.getBuiltInNamespace() + "' not allowed";
Expand All @@ -63,14 +70,16 @@ public LocalVSCodeService(
SearchUtilService search,
StorageUtilService storageUtil,
ExtensionVersionIntegrityService integrityService,
WebResourceService webResources
WebResourceService webResources,
CacheService cache
) {
this.repositories = repositories;
this.versions = versions;
this.search = search;
this.storageUtil = storageUtil;
this.integrityService = integrityService;
this.webResources = webResources;
this.cache = cache;
}

@Override
Expand Down Expand Up @@ -319,17 +328,26 @@ public ResponseEntity<StreamingResponseBody> getAsset(
return storageUtil.getFileResponse(resource);
} else if(asset.startsWith(FILE_WEB_RESOURCES + "/extension/")) {
var name = asset.substring((FILE_WEB_RESOURCES.length() + 1));
var file = webResources.getWebResource(namespace, extensionName, targetPlatform, version, name, false);
if(file == null) {
throw new NotFoundException();
}

var file = getWebResource(namespace, extensionName, targetPlatform, version, name, false);
return storageUtil.getFileResponse(file);
}

throw new NotFoundException();
}

private Path getWebResource(String namespaceName, String extensionName, String targetPlatform, String version, String name, boolean browse) {
var file = webResources.getWebResource(namespaceName, extensionName, targetPlatform, version, name, browse);
if(file == null) {
throw new NotFoundException();
}
if(!Files.exists(file)) {
logger.error("File doesn't exist {}", file);
cache.evictWebResourceFile(namespaceName, extensionName, null, version, name);
throw new NotFoundException();
}
return file;
}

private String builtinExtensionMessage() {
return "Built-in extension namespace '" + BuiltInExtensionUtil.getBuiltInNamespace() + "' not allowed";
}
Expand Down Expand Up @@ -381,11 +399,7 @@ public ResponseEntity<StreamingResponseBody> browse(String namespaceName, String
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(builtinExtensionResponse);
}

var file = webResources.getWebResource(namespaceName, extensionName, null, version, path, true);
if(file == null) {
throw new NotFoundException();
}

var file = getWebResource(namespaceName, extensionName, null, version, path, true);
return storageUtil.getFileResponse(file);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
package org.eclipse.openvsx.adapter;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.openvsx.cache.CacheService;
import org.eclipse.openvsx.entities.FileResource;
import org.eclipse.openvsx.repositories.RepositoryService;
import org.eclipse.openvsx.storage.StorageUtilService;
import org.eclipse.openvsx.util.ErrorResultException;
import org.eclipse.openvsx.util.NamingUtil;
import org.eclipse.openvsx.util.UrlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

Expand All @@ -32,12 +35,16 @@
@Component
public class WebResourceService {

protected final Logger logger = LoggerFactory.getLogger(WebResourceService.class);

private final StorageUtilService storageUtil;
private final RepositoryService repositories;
private final CacheService cache;

public WebResourceService(StorageUtilService storageUtil, RepositoryService repositories) {
public WebResourceService(StorageUtilService storageUtil, RepositoryService repositories, CacheService cache) {
this.storageUtil = storageUtil;
this.repositories = repositories;
this.cache = cache;
}

@Cacheable(value = CACHE_WEB_RESOURCE_FILES, keyGenerator = GENERATOR_FILES)
Expand All @@ -56,6 +63,11 @@ public Path getWebResource(String namespace, String extension, String targetPlat
if(path == null) {
return null;
}
if(!Files.exists(path)) {
logger.error("File doesn't exist {}", path);
cache.evictExtensionFile(download);
return null;
}

try(var zip = new ZipFile(path.toFile())) {
var fileEntry = zip.getEntry(name);
Expand Down
24 changes: 23 additions & 1 deletion server/src/main/java/org/eclipse/openvsx/cache/CacheService.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import org.eclipse.openvsx.entities.Extension;
import org.eclipse.openvsx.entities.ExtensionVersion;
import org.eclipse.openvsx.entities.FileResource;
import org.eclipse.openvsx.entities.UserData;
import org.eclipse.openvsx.repositories.RepositoryService;
import org.eclipse.openvsx.util.TargetPlatform;
Expand Down Expand Up @@ -42,17 +43,20 @@ public class CacheService {
private final RepositoryService repositories;
private final ExtensionJsonCacheKeyGenerator extensionJsonCacheKey;
private final LatestExtensionVersionCacheKeyGenerator latestExtensionVersionCacheKey;
private final FilesCacheKeyGenerator filesCacheKeyGenerator;

public CacheService(
CacheManager cacheManager,
RepositoryService repositories,
ExtensionJsonCacheKeyGenerator extensionJsonCacheKey,
LatestExtensionVersionCacheKeyGenerator latestExtensionVersionCacheKey
LatestExtensionVersionCacheKeyGenerator latestExtensionVersionCacheKey,
FilesCacheKeyGenerator filesCacheKeyGenerator
) {
this.cacheManager = cacheManager;
this.repositories = repositories;
this.extensionJsonCacheKey = extensionJsonCacheKey;
this.latestExtensionVersionCacheKey = latestExtensionVersionCacheKey;
this.filesCacheKeyGenerator = filesCacheKeyGenerator;
}

public void evictNamespaceDetails() {
Expand Down Expand Up @@ -154,4 +158,22 @@ private void invalidateCache(String cacheName) {

cache.invalidate();
}

public void evictExtensionFile(FileResource download) {
var cache = cacheManager.getCache(CACHE_EXTENSION_FILES);
if(cache == null) {
return;
}

cache.evict(filesCacheKeyGenerator.generate(download));
}

public void evictWebResourceFile(String namespaceName, String extensionName, String targetPlatform, String version, String path) {
var cache = cacheManager.getCache(CACHE_WEB_RESOURCE_FILES);
if(cache == null) {
return;
}

cache.evict(filesCacheKeyGenerator.generate(namespaceName, extensionName, targetPlatform, version, path));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,20 @@ public Object generate(Object target, Method method, Object... params) {
return generate(namespace, extension, targetPlatform, version, name);
}
if(target instanceof IStorageService) {
var resource = (FileResource) params[0];
var extVersion = resource.getExtension();
var extension = extVersion.getExtension();
var namespace = extension.getNamespace();
return generate(namespace.getName(), extension.getName(), extVersion.getTargetPlatform(), extVersion.getVersion(), resource.getName());
return generate((FileResource) params[0]);
}

throw new UnsupportedOperationException();
}

private String generate(String namespace, String extension, String targetPlatform, String version, String name) {
public String generate(FileResource resource) {
var extVersion = resource.getExtension();
var extension = extVersion.getExtension();
var namespace = extension.getNamespace();
return generate(namespace.getName(), extension.getName(), extVersion.getTargetPlatform(), extVersion.getVersion(), resource.getName());
}

public String generate(String namespace, String extension, String targetPlatform, String version, String name) {
return UrlUtil.createApiFileUrl("", namespace, extension, targetPlatform, version, name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -933,8 +933,8 @@ TokenService tokenService(
}

@Bean
WebResourceService webResourceService(StorageUtilService storageUtil, RepositoryService repositories) {
return new WebResourceService(storageUtil, repositories);
WebResourceService webResourceService(StorageUtilService storageUtil, RepositoryService repositories, CacheService cache) {
return new WebResourceService(storageUtil, repositories, cache);
}

@Bean
Expand All @@ -944,9 +944,10 @@ LocalVSCodeService localVSCodeService(
SearchUtilService search,
StorageUtilService storageUtil,
ExtensionVersionIntegrityService integrityService,
WebResourceService webResourceService
WebResourceService webResourceService,
CacheService cache
) {
return new LocalVSCodeService(repositories, versions, search, storageUtil, integrityService, webResourceService);
return new LocalVSCodeService(repositories, versions, search, storageUtil, integrityService, webResourceService, cache);
}

@Bean
Expand Down