diff options
Diffstat (limited to 'org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server')
11 files changed, 1378 insertions, 0 deletions
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LargeFileRepository.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LargeFileRepository.java new file mode 100644 index 0000000000..3bdf8d08b2 --- /dev/null +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LargeFileRepository.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lfs.server; + +import java.io.IOException; + +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.lfs.lib.AnyLongObjectId; + +/** + * Abstraction of a repository for storing large objects + * + * @since 4.3 + */ +public interface LargeFileRepository { + + /** + * @param id + * id of the object to download + * @return Action for downloading the object + */ + public Response.Action getDownloadAction(AnyLongObjectId id); + + /** + * @param id + * id of the object to upload + * @param size + * size of the object to be uploaded + * @return Action for uploading the object + */ + public Response.Action getUploadAction(AnyLongObjectId id, long size); + + /** + * @param id + * id of the object to be verified + * @return Action for verifying the object, or {@code null} if the server + * doesn't support or require verification + */ + public @Nullable Response.Action getVerifyAction(AnyLongObjectId id); + + /** + * @param id + * id of the object + * @return length of the object content in bytes, -1 if the object doesn't + * exist + * @throws IOException + */ + public long getSize(AnyLongObjectId id) throws IOException; +} diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsObject.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsObject.java new file mode 100644 index 0000000000..30ba22e885 --- /dev/null +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsObject.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015, Sasa Zivkov <sasa.zivkov@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lfs.server; + +class LfsObject { + String oid; + long size; +} diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java new file mode 100644 index 0000000000..394137cf68 --- /dev/null +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/LfsProtocolServlet.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2015, Sasa Zivkov <sasa.zivkov@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lfs.server; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static javax.servlet.http.HttpServletResponse.SC_OK; +import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +/** + * LFS protocol handler implementing the LFS batch API [1] + * + * [1] https://github.com/github/git-lfs/blob/master/docs/api/http-v1-batch.md + * + * @since 4.3 + */ +public abstract class LfsProtocolServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + private static final String CONTENTTYPE_VND_GIT_LFS_JSON = "application/vnd.git-lfs+json"; //$NON-NLS-1$ + + private Gson gson = createGson(); + + /** + * Get the large file repository + * + * @return the large file repository storing large files + */ + protected abstract LargeFileRepository getLargeFileRepository(); + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse res) + throws ServletException, IOException { + res.setStatus(SC_OK); + res.setContentType(CONTENTTYPE_VND_GIT_LFS_JSON); + + Writer w = new BufferedWriter( + new OutputStreamWriter(res.getOutputStream(), UTF_8)); + + Reader r = new BufferedReader(new InputStreamReader(req.getInputStream(), UTF_8)); + LfsRequest request = gson.fromJson(r, LfsRequest.class); + + LargeFileRepository repo = getLargeFileRepository(); + if (repo == null) { + res.setStatus(SC_SERVICE_UNAVAILABLE); + return; + } + + TransferHandler handler = TransferHandler + .forOperation(request.operation, repo, request.objects); + gson.toJson(handler.process(), w); + w.flush(); + } + + private static class LfsRequest { + String operation; + + List<LfsObject> objects; + } + + private static Gson createGson() { + GsonBuilder gb = new GsonBuilder() + .setFieldNamingPolicy( + FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .setPrettyPrinting().disableHtmlEscaping(); + return gb.create(); + } +} diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/Response.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/Response.java new file mode 100644 index 0000000000..dc972e04ee --- /dev/null +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/Response.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2015, Sasa Zivkov <sasa.zivkov@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lfs.server; + +import java.util.List; +import java.util.Map; + +/** + * POJOs for Gson serialization/deserialization + * + * See + * {@link <a href="https://github.com/github/git-lfs/tree/master/docs/api">LFS + * API specification</a>} + * + * @since 4.3 + */ +public interface Response { + /** Describes an action the client can execute on a single object */ + class Action { + public String href; + public Map<String, String> header; + } + + /** Describes an error to be returned by the LFS batch API */ + class Error { + public int code; + public String message; + } + + /** Describes the actions the LFS server offers for a single object */ + class ObjectInfo { + public String oid; + public long size; + public Map<String, Action> actions; + public Error error; + } + + /** Describes the body of a LFS batch API response */ + class Body { + public List<ObjectInfo> objects; + } +} diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/TransferHandler.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/TransferHandler.java new file mode 100644 index 0000000000..bf5b61cc6e --- /dev/null +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/TransferHandler.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2015, Sasa Zivkov <sasa.zivkov@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.lfs.server; + +import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.eclipse.jgit.lfs.lib.LongObjectId; +import org.eclipse.jgit.lfs.server.Response.Action; +import org.eclipse.jgit.lfs.server.Response.Body; +import org.eclipse.jgit.lfs.server.internal.LfsServerText; + +abstract class TransferHandler { + + private static final String DOWNLOAD = "download"; //$NON-NLS-1$ + private static final String UPLOAD = "upload"; //$NON-NLS-1$ + private static final String VERIFY = "verify"; //$NON-NLS-1$ + + static TransferHandler forOperation(String operation, + LargeFileRepository repository, List<LfsObject> objects) { + switch (operation) { + case TransferHandler.UPLOAD: + return new Upload(repository, objects); + case TransferHandler.DOWNLOAD: + return new Download(repository, objects); + case TransferHandler.VERIFY: + default: + throw new UnsupportedOperationException(MessageFormat.format( + LfsServerText.get().unsupportedOperation, operation)); + } + } + + private static class Upload extends TransferHandler { + Upload(LargeFileRepository repository, + List<LfsObject> objects) { + super(repository, objects); + } + + @Override + Body process() throws IOException { + Response.Body body = new Response.Body(); + if (objects.size() > 0) { + body.objects = new ArrayList<>(); + for (LfsObject o : objects) { + addObjectInfo(body, o); + } + } + return body; + } + + private void addObjectInfo(Response.Body body, LfsObject o) + throws IOException { + Response.ObjectInfo info = new Response.ObjectInfo(); + body.objects.add(info); + info.oid = o.oid; + info.size = o.size; + + LongObjectId oid = LongObjectId.fromString(o.oid); + if (repository.getSize(oid) == -1) { + info.actions = new HashMap<>(); + info.actions.put(UPLOAD, + repository.getUploadAction(oid, o.size)); + Action verify = repository.getVerifyAction(oid); + if (verify != null) { + info.actions.put(VERIFY, verify); + } + } + } + } + + private static class Download extends TransferHandler { + Download(LargeFileRepository repository, + List<LfsObject> objects) { + super(repository, objects); + } + + @Override + Body process() throws IOException { + Response.Body body = new Response.Body(); + if (objects.size() > 0) { + body.objects = new ArrayList<>(); + for (LfsObject o : objects) { + addObjectInfo(body, o); + } + } + return body; + } + + private void addObjectInfo(Response.Body body, LfsObject o) + throws IOException { + Response.ObjectInfo info = new Response.ObjectInfo(); + body.objects.add(info); + info.oid = o.oid; + info.size = o.size; + + LongObjectId oid = LongObjectId.fromString(o.oid); + if (repository.getSize(oid) >= 0) { + info.actions = new HashMap<>(); + info.actions.put(DOWNLOAD, + repository.getDownloadAction(oid)); + } else { + info.error = new Response.Error(); + info.error.code = SC_NOT_FOUND; + info.error.message = MessageFormat.format( + LfsServerText.get().objectNotFound, + oid.getName()); + } + } + } + + final LargeFileRepository repository; + + final List<LfsObject> objects; + + TransferHandler(LargeFileRepository repository, + List<LfsObject> objects) { + this.repository = repository; + this.objects = objects; + } + + abstract Response.Body process() throws IOException; +}
\ No newline at end of file diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/AtomicObjectOutputStream.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/AtomicObjectOutputStream.java new file mode 100644 index 0000000000..ecc7c1f36c --- /dev/null +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/AtomicObjectOutputStream.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lfs.server.fs; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Path; +import java.security.DigestOutputStream; +import java.text.MessageFormat; + +import org.eclipse.jgit.internal.storage.file.LockFile; +import org.eclipse.jgit.lfs.errors.CorruptLongObjectException; +import org.eclipse.jgit.lfs.lib.AnyLongObjectId; +import org.eclipse.jgit.lfs.lib.Constants; +import org.eclipse.jgit.lfs.lib.LongObjectId; +import org.eclipse.jgit.lfs.server.internal.LfsServerText; + +/** + * Output stream writing content to a {@link LockFile} which is committed on + * close(). The stream checks if the hash of the stream content matches the + * id. + */ +class AtomicObjectOutputStream extends OutputStream { + + private LockFile locked; + + private DigestOutputStream out; + + private boolean aborted; + + private AnyLongObjectId id; + + AtomicObjectOutputStream(Path path, AnyLongObjectId id) + throws IOException { + locked = new LockFile(path.toFile()); + locked.lock(); + this.id = id; + out = new DigestOutputStream(locked.getOutputStream(), + Constants.newMessageDigest()); + } + + @Override + public void write(int b) throws IOException { + out.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + out.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + out.write(b, off, len); + } + + @Override + public void close() throws IOException { + out.close(); + if (!aborted) { + verifyHash(); + locked.commit(); + } + } + + private void verifyHash() { + AnyLongObjectId contentHash = LongObjectId + .fromRaw(out.getMessageDigest().digest()); + if (!contentHash.equals(id)) { + abort(); + throw new CorruptLongObjectException(id, contentHash, + MessageFormat.format(LfsServerText.get().corruptLongObject, + contentHash, id)); + } + } + + void abort() { + locked.unlock(); + aborted = true; + } +}
\ No newline at end of file diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java new file mode 100644 index 0000000000..12da271b37 --- /dev/null +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lfs.server.fs; + +import static org.eclipse.jgit.util.HttpSupport.HDR_AUTHORIZATION; + +import java.io.IOException; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Collections; + +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.lfs.lib.AnyLongObjectId; +import org.eclipse.jgit.lfs.lib.Constants; +import org.eclipse.jgit.lfs.server.LargeFileRepository; +import org.eclipse.jgit.lfs.server.Response; +import org.eclipse.jgit.lfs.server.Response.Action; + +/** + * Repository storing large objects in the file system + * + * @since 4.3 + */ +public class FileLfsRepository implements LargeFileRepository { + + private final String url; + private final Path dir; + private AtomicObjectOutputStream out; + + /** + * @param url + * external URL of this repository + * @param dir + * storage directory + * @throws IOException + */ + public FileLfsRepository(String url, Path dir) throws IOException { + this.url = url; + this.dir = dir; + Files.createDirectories(dir); + } + + @Override + public Response.Action getDownloadAction(AnyLongObjectId id) { + return getAction(id); + } + + @Override + public Action getUploadAction(AnyLongObjectId id, long size) { + return getAction(id); + } + + @Override + public @Nullable Action getVerifyAction(AnyLongObjectId id) { + return null; + } + + @Override + public long getSize(AnyLongObjectId id) throws IOException { + Path p = getPath(id); + if (Files.exists(p)) { + return Files.size(p); + } else { + return -1; + } + } + + /** + * Get the storage directory + * + * @return the path of the storage directory + */ + public Path getDir() { + return dir; + } + + /** + * Get the path where the given object is stored + * + * @param id + * id of a large object + * @return path the object's storage path + */ + protected Path getPath(AnyLongObjectId id) { + StringBuilder s = new StringBuilder( + Constants.LONG_OBJECT_ID_STRING_LENGTH + 6); + s.append(toHexCharArray(id.getFirstByte())).append('/'); + s.append(toHexCharArray(id.getSecondByte())).append('/'); + s.append(id.name()); + return dir.resolve(s.toString()); + } + + private Response.Action getAction(AnyLongObjectId id) { + Response.Action a = new Response.Action(); + a.href = url + id.getName(); + a.header = Collections.singletonMap(HDR_AUTHORIZATION, "not:required"); //$NON-NLS-1$ + return a; + } + + ReadableByteChannel getReadChannel(AnyLongObjectId id) + throws IOException { + return FileChannel.open(getPath(id), StandardOpenOption.READ); + } + + WritableByteChannel getWriteChannel(AnyLongObjectId id) + throws IOException { + Path path = getPath(id); + Files.createDirectories(path.getParent()); + out = new AtomicObjectOutputStream(path, id); + return Channels.newChannel(out); + } + + /** + * Abort the output stream + */ + void abortWrite() { + if (out != null) { + out.abort(); + } + } + + private static char[] toHexCharArray(int b) { + final char[] dst = new char[2]; + formatHexChar(dst, 0, b); + return dst; + } + + private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6', + '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + private static void formatHexChar(final char[] dst, final int p, int b) { + int o = p + 1; + while (o >= p && b != 0) { + dst[o--] = hexchar[b & 0xf]; + b >>>= 4; + } + while (o >= p) + dst[o--] = '0'; + } +} diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java new file mode 100644 index 0000000000..8864af87ab --- /dev/null +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lfs.server.fs; + +import java.io.IOException; +import java.text.MessageFormat; + +import javax.servlet.AsyncContext; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.HttpStatus; +import org.eclipse.jgit.lfs.errors.InvalidLongObjectIdException; +import org.eclipse.jgit.lfs.lib.AnyLongObjectId; +import org.eclipse.jgit.lfs.lib.Constants; +import org.eclipse.jgit.lfs.lib.LongObjectId; +import org.eclipse.jgit.lfs.server.internal.LfsServerText; + +/** + * Servlet supporting upload and download of large objects as defined by the + * GitHub Large File Storage extension API extending git to allow separate + * storage of large files + * (https://github.com/github/git-lfs/tree/master/docs/api). + * + * @since 4.3 + */ +@WebServlet(asyncSupported = true) +public class FileLfsServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + private final FileLfsRepository repository; + + private final long timeout; + + /** + * @param repository + * the repository storing the large objects + * @param timeout + * timeout for object upload / download in milliseconds + */ + public FileLfsServlet(FileLfsRepository repository, long timeout) { + this.repository = repository; + this.timeout = timeout; + } + + /** + * Handles object downloads + * + * @param req + * servlet request + * @param rsp + * servlet response + * @throws ServletException + * if a servlet-specific error occurs + * @throws IOException + * if an I/O error occurs + */ + @Override + protected void doGet(HttpServletRequest req, + HttpServletResponse rsp) throws ServletException, IOException { + AnyLongObjectId obj = getObjectToTransfer(req, rsp); + if (obj != null) { + if (repository.getSize(obj) == -1) { + sendError(rsp, HttpStatus.SC_NOT_FOUND, MessageFormat + .format(LfsServerText.get().objectNotFound, obj)); + return; + } + AsyncContext context = req.startAsync(); + context.setTimeout(timeout); + rsp.getOutputStream() + .setWriteListener(new ObjectDownloadListener(repository, + context, rsp, obj)); + } + } + + private AnyLongObjectId getObjectToTransfer(HttpServletRequest req, + HttpServletResponse rsp) throws IOException { + String info = req.getPathInfo(); + if (info.length() != 1 + Constants.LONG_OBJECT_ID_STRING_LENGTH) { + sendError(rsp, HttpStatus.SC_BAD_REQUEST, MessageFormat + .format(LfsServerText.get().invalidPathInfo, info)); + return null; + } + try { + return LongObjectId.fromString(info.substring(1, 65)); + } catch (InvalidLongObjectIdException e) { + sendError(rsp, HttpStatus.SC_BAD_REQUEST, e.getMessage()); + return null; + } + } + + /** + * Handle object uploads + * + * @param req + * servlet request + * @param rsp + * servlet response + * @throws ServletException + * if a servlet-specific error occurs + * @throws IOException + * if an I/O error occurs + */ + @Override + protected void doPut(HttpServletRequest req, + HttpServletResponse rsp) throws ServletException, IOException { + AnyLongObjectId id = getObjectToTransfer(req, rsp); + if (id != null) { + AsyncContext context = req.startAsync(); + context.setTimeout(timeout); + req.getInputStream().setReadListener(new ObjectUploadListener( + repository, context, req, rsp, id)); + } + } + + static void sendError(HttpServletResponse rsp, int status, String message) + throws IOException { + rsp.setStatus(status); + // TODO return message in response body in json format as specified in + // https://github.com/github/git-lfs/blob/master/docs/api/http-v1-batch.md + rsp.flushBuffer(); + } +} diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java new file mode 100644 index 0000000000..bfdea4fb1d --- /dev/null +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2015, Matthias Sohn <matthias.sohnk@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lfs.server.fs; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.servlet.AsyncContext; +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.HttpStatus; +import org.eclipse.jgit.lfs.lib.AnyLongObjectId; +import org.eclipse.jgit.lfs.lib.Constants; +import org.eclipse.jgit.util.HttpSupport; + +/** + * Handle asynchronous large object download + */ +class ObjectDownloadListener implements WriteListener { + + private static Logger LOG = Logger + .getLogger(ObjectDownloadListener.class.getName()); + + private final AsyncContext context; + + private final HttpServletResponse response; + + private final ServletOutputStream out; + + private final ReadableByteChannel in; + + private final WritableByteChannel outChannel; + + private final ByteBuffer buffer = ByteBuffer.allocateDirect(8192); + + /** + * @param repository + * the repository storing large objects + * @param context + * the servlet asynchronous context + * @param response + * the servlet response + * @param id + * id of the object to be downloaded + * @throws IOException + */ + public ObjectDownloadListener(FileLfsRepository repository, + AsyncContext context, HttpServletResponse response, + AnyLongObjectId id) throws IOException { + this.context = context; + this.response = response; + this.in = repository.getReadChannel(id); + this.out = response.getOutputStream(); + this.outChannel = Channels.newChannel(out); + + response.addHeader(HttpSupport.HDR_CONTENT_LENGTH, + String.valueOf(repository.getSize(id))); + response.setContentType(Constants.HDR_APPLICATION_OCTET_STREAM); + } + + /** + * Write file content + * + * @throws IOException + */ + @Override + public void onWritePossible() throws IOException { + while (out.isReady()) { + if (in.read(buffer) != -1) { + buffer.flip(); + outChannel.write(buffer); + buffer.compact(); + } else { + in.close(); + buffer.flip(); + while (out.isReady()) { + if (buffer.hasRemaining()) { + outChannel.write(buffer); + } else { + context.complete(); + } + } + } + } + } + + /** + * Handle errors + * + * @param e + * the cause + */ + @Override + public void onError(Throwable e) { + try { + FileLfsServlet.sendError(response, + HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + context.complete(); + in.close(); + } catch (IOException ex) { + LOG.log(Level.SEVERE, ex.getMessage(), ex); + } + } +} diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java new file mode 100644 index 0000000000..05970ad1f2 --- /dev/null +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2015, Matthias Sohn <matthias.sohnk@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lfs.server.fs; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.servlet.AsyncContext; +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.HttpStatus; +import org.eclipse.jgit.lfs.errors.CorruptLongObjectException; +import org.eclipse.jgit.lfs.lib.AnyLongObjectId; +import org.eclipse.jgit.lfs.lib.Constants; + +/** + * Handle asynchronous object upload + */ +class ObjectUploadListener implements ReadListener { + + private static Logger LOG = Logger + .getLogger(ObjectUploadListener.class.getName()); + + private final AsyncContext context; + + private final HttpServletResponse response; + + private FileLfsRepository repository; + + private final ServletInputStream in; + + private final ReadableByteChannel inChannel; + + private WritableByteChannel out; + + private final ByteBuffer buffer = ByteBuffer.allocateDirect(8192); + + /** + * @param repository + * the repository storing large objects + * @param context + * @param request + * @param response + * @param id + * @throws FileNotFoundException + * @throws IOException + */ + public ObjectUploadListener(FileLfsRepository repository, + AsyncContext context, HttpServletRequest request, + HttpServletResponse response, AnyLongObjectId id) + throws FileNotFoundException, IOException { + this.repository = repository; + this.context = context; + this.response = response; + this.in = request.getInputStream(); + this.inChannel = Channels.newChannel(in); + this.out = repository.getWriteChannel(id); + response.setContentType(Constants.CONTENT_TYPE_GIT_LFS_JSON); + } + + /** + * Writes all the received data to the output channel + * + * @throws IOException + */ + @Override + public void onDataAvailable() throws IOException { + while (in.isReady()) { + if (inChannel.read(buffer) > 0) { + buffer.flip(); + out.write(buffer); + buffer.compact(); + } else { + buffer.flip(); + while (buffer.hasRemaining()) { + out.write(buffer); + } + close(); + return; + } + } + } + + /** + * @throws IOException + */ + @Override + public void onAllDataRead() throws IOException { + close(); + } + + protected void close() throws IOException { + try { + inChannel.close(); + out.close(); + // TODO check if status 200 is ok for PUT request, HTTP foresees 204 + // for successful PUT without response body + response.setStatus(HttpServletResponse.SC_OK); + } finally { + context.complete(); + } + } + + /** + * @param e + * the exception that caused the problem + */ + @Override + public void onError(Throwable e) { + try { + repository.abortWrite(); + inChannel.close(); + out.close(); + int status; + if (e instanceof CorruptLongObjectException) { + status = HttpStatus.SC_BAD_REQUEST; + LOG.log(Level.WARNING, e.getMessage(), e); + } else { + status = HttpStatus.SC_INTERNAL_SERVER_ERROR; + LOG.log(Level.SEVERE, e.getMessage(), e); + } + FileLfsServlet.sendError(response, status, e.getMessage()); + } catch (IOException ex) { + LOG.log(Level.SEVERE, ex.getMessage(), ex); + } + } +}
\ No newline at end of file diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsServerText.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsServerText.java new file mode 100644 index 0000000000..4e1c4c639e --- /dev/null +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/internal/LfsServerText.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lfs.server.internal; + +import org.eclipse.jgit.nls.NLS; +import org.eclipse.jgit.nls.TranslationBundle; + +/** + * Translation bundle for JGit LFS server + */ +public class LfsServerText extends TranslationBundle { + + /** + * @return an instance of this translation bundle + */ + public static LfsServerText get() { + return NLS.getBundleFor(LfsServerText.class); + } + + // @formatter:off + /***/ public String corruptLongObject; + /***/ public String invalidPathInfo; + /***/ public String objectNotFound; + /***/ public String unsupportedOperation; +} |