com.google.appengine.api.blobstore.dev.LocalBlobstoreService Maven / Gradle / Ivy
Go to download
SDK for dev_appserver (local development) with some of the dependencies shaded (repackaged)
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.appengine.api.blobstore.dev;
import static com.google.appengine.repackaged.com.google.common.io.BaseEncoding.base64Url;
import com.google.appengine.api.blobstore.BlobInfo;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServicePb.BlobstoreServiceError;
import com.google.appengine.api.blobstore.BlobstoreServicePb.CreateEncodedGoogleStorageKeyRequest;
import com.google.appengine.api.blobstore.BlobstoreServicePb.CreateEncodedGoogleStorageKeyResponse;
import com.google.appengine.api.blobstore.BlobstoreServicePb.CreateUploadURLRequest;
import com.google.appengine.api.blobstore.BlobstoreServicePb.CreateUploadURLResponse;
import com.google.appengine.api.blobstore.BlobstoreServicePb.DeleteBlobRequest;
import com.google.appengine.api.blobstore.BlobstoreServicePb.FetchDataRequest;
import com.google.appengine.api.blobstore.BlobstoreServicePb.FetchDataResponse;
import com.google.appengine.tools.development.AbstractLocalRpcService;
import com.google.appengine.tools.development.LocalRpcService;
import com.google.appengine.tools.development.LocalServiceContext;
import com.google.apphosting.api.ApiProxy;
import com.google.apphosting.base.protos.api.ApiBasePb.VoidProto;
import com.google.apphosting.utils.config.GenerationDirectory;
import com.google.auto.service.AutoService;
import com.google.appengine.repackaged.com.google.common.io.ByteStreams;
import com.google.appengine.repackaged.com.google.common.io.Closeables;
import com.google.appengine.repackaged.com.google.common.io.Files;
import com.google.appengine.repackaged.com.google.protobuf.ByteString;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Implementation of local blobstore service.
*
*/
@AutoService(LocalRpcService.class)
public final class LocalBlobstoreService extends AbstractLocalRpcService {
// Environment attribute key where the instance port is stored. This must match
// com.google.appengine.tools.development.LocalEnvironment.PORT_ID_ENV_ATTRIBUTE but
// cannot access that definition due to packaging for unit tests.
private static final String PORT_ID_ENV_ATTRIBUTE = "com.google.appengine.instance.port";
private static final Logger logger = Logger.getLogger(
LocalBlobstoreService.class.getName());
/**
* Where to read/store the blobs from/to.
*/
public static final String BACKING_STORE_PROPERTY = "blobstore.backing_store";
/**
* True to put the blobstore into "memory-only" mode.
*/
public static final String NO_STORAGE_PROPERTY = "blobstore.no_storage";
/**
* The package name for this service.
*/
public static final String PACKAGE = "blobstore";
/**
* The prefix we apply to encoded Google Storage BlobKeys
*/
public static final String GOOGLE_STORAGE_KEY_PREFIX = "encoded_gs_key:";
static final String UPLOAD_URL_PREFIX = "/_ah/upload/";
private BlobStorage blobStorage;
private BlobUploadSessionStorage uploadSessionStorage;
private String serverHostName;
@Override
public String getPackage() {
return PACKAGE;
}
@Override
public void init(LocalServiceContext context, Map properties) {
uploadSessionStorage = new BlobUploadSessionStorage();
String noStorage = properties.get(NO_STORAGE_PROPERTY);
if (noStorage != null && Boolean.parseBoolean(noStorage)) {
BlobStorageFactory.setMemoryBlobStorage();
} else {
String filePath = properties.get(BACKING_STORE_PROPERTY);
File file;
if (filePath != null) {
logger.log(Level.INFO, "Creating blobstore backing store at " + filePath);
file = new File(filePath);
} else {
file = GenerationDirectory.getGenerationDirectory(
context.getLocalServerEnvironment().getAppDir());
}
file.mkdirs();
if (!file.canWrite()) {
logger.log(Level.WARNING, "Default blobstore file location is not writable, " +
"creating a temporary directory. State will not be persisted between restarts.");
file = Files.createTempDir();
}
BlobStorageFactory.setFileBlobStorage(file);
}
blobStorage = BlobStorageFactory.getBlobStorage();
serverHostName = context.getLocalServerEnvironment().getHostName();
}
@Override
public void start() {
}
@Override
public void stop() {
if (blobStorage instanceof MemoryBlobStorage) {
((MemoryBlobStorage) blobStorage).deleteAllBlobs();
}
}
public CreateUploadURLResponse createUploadURL(Status status, CreateUploadURLRequest request) {
BlobUploadSession session = new BlobUploadSession(request.getSuccessPath());
if (request.hasMaxUploadSizePerBlobBytes()) {
session.setMaxUploadSizeBytesPerBlob(request.getMaxUploadSizePerBlobBytes());
}
if (request.hasMaxUploadSizeBytes()) {
session.setMaxUploadSizeBytes(request.getMaxUploadSizeBytes());
}
if (request.hasGsBucketName()) {
session.setGoogleStorageBucketName(request.getGsBucketName());
}
String sessionId = uploadSessionStorage.createSession(session);
CreateUploadURLResponse.Builder response = CreateUploadURLResponse.newBuilder();
String url = String.format("http://%s:%s%s%s", serverHostName, getCurrentInstancePort(),
UPLOAD_URL_PREFIX, sessionId);
response.setUrl(url);
return response.build();
}
public VoidProto deleteBlob(Status status, final DeleteBlobRequest request) {
AccessController.doPrivileged(
(PrivilegedAction