James Moger
2015-11-22 ed552ba47c02779c270ffd62841d6d1048dade70
commit | author | age
5e3521 1 /*
JM 2  * Copyright 2014 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.gitblit.servlet;
17
efdb2b 18 import java.io.ByteArrayOutputStream;
5e3521 19 import java.io.File;
JM 20 import java.io.FileInputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24
cdb2fe 25 import com.google.inject.Inject;
JM 26 import com.google.inject.Singleton;
5e3521 27 import javax.servlet.ServletException;
1b34b0 28 import javax.servlet.http.HttpServlet;
5e3521 29 import javax.servlet.http.HttpServletRequest;
JM 30 import javax.servlet.http.HttpServletResponse;
31
32 import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
33 import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
34 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
35 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
36 import org.apache.commons.compress.compressors.CompressorOutputStream;
37 import org.apache.commons.compress.compressors.CompressorStreamFactory;
38 import org.eclipse.jgit.lib.FileMode;
39
40 import com.gitblit.manager.IRuntimeManager;
41
42 /**
43  * Handles requests for the Barnum pt (patchset tool).
44  *
45  * The user-agent determines the content and compression format.
46  *
47  * @author James Moger
48  *
49  */
1b34b0 50 @Singleton
JM 51 public class PtServlet extends HttpServlet {
5e3521 52
JM 53     private static final long serialVersionUID = 1L;
54
55     private static final long lastModified = System.currentTimeMillis();
56
57     private IRuntimeManager runtimeManager;
58
1b34b0 59     @Inject
JM 60     public PtServlet(IRuntimeManager runtimeManager) {
61         this.runtimeManager = runtimeManager;
5e3521 62     }
JM 63
64     @Override
65     protected long getLastModified(HttpServletRequest req) {
66         File file = runtimeManager.getFileOrFolder("tickets.pt", "${baseFolder}/pt.py");
67         if (file.exists()) {
68             return Math.max(lastModified, file.lastModified());
69         } else {
70             return lastModified;
71         }
72     }
73
74     @Override
75     protected void doGet(HttpServletRequest request, HttpServletResponse response)
76             throws ServletException, IOException {
77         try {
78             response.setContentType("application/octet-stream");
79             response.setDateHeader("Last-Modified", lastModified);
80             response.setHeader("Cache-Control", "none");
81             response.setHeader("Pragma", "no-cache");
82             response.setDateHeader("Expires", 0);
83
84             boolean windows = false;
85             try {
86                 String useragent = request.getHeader("user-agent").toString();
87                 windows = useragent.toLowerCase().contains("windows");
88             } catch (Exception e) {
89             }
90
91             byte[] pyBytes;
92             File file = runtimeManager.getFileOrFolder("tickets.pt", "${baseFolder}/pt.py");
93             if (file.exists()) {
94                 // custom script
95                 pyBytes = readAll(new FileInputStream(file));
96             } else {
97                 // default script
98                 pyBytes = readAll(getClass().getResourceAsStream("/pt.py"));
99             }
100
101             if (windows) {
102                 // windows: download zip file with pt.py and pt.cmd
103                 response.setHeader("Content-Disposition", "attachment; filename=\"pt.zip\"");
104
105                 OutputStream os = response.getOutputStream();
106                 ZipArchiveOutputStream zos = new ZipArchiveOutputStream(os);
107
108                 // add the Python script
109                 ZipArchiveEntry pyEntry = new ZipArchiveEntry("pt.py");
110                 pyEntry.setSize(pyBytes.length);
111                 pyEntry.setUnixMode(FileMode.EXECUTABLE_FILE.getBits());
112                 pyEntry.setTime(lastModified);
113                 zos.putArchiveEntry(pyEntry);
114                 zos.write(pyBytes);
115                 zos.closeArchiveEntry();
116
117                 // add a Python launch cmd file
118                 byte [] cmdBytes = readAll(getClass().getResourceAsStream("/pt.cmd"));
119                 ZipArchiveEntry cmdEntry = new ZipArchiveEntry("pt.cmd");
120                 cmdEntry.setSize(cmdBytes.length);
121                 cmdEntry.setUnixMode(FileMode.REGULAR_FILE.getBits());
122                 cmdEntry.setTime(lastModified);
123                 zos.putArchiveEntry(cmdEntry);
124                 zos.write(cmdBytes);
125                 zos.closeArchiveEntry();
126
127                 // add a brief readme
128                 byte [] txtBytes = readAll(getClass().getResourceAsStream("/pt.txt"));
129                 ZipArchiveEntry txtEntry = new ZipArchiveEntry("readme.txt");
130                 txtEntry.setSize(txtBytes.length);
131                 txtEntry.setUnixMode(FileMode.REGULAR_FILE.getBits());
132                 txtEntry.setTime(lastModified);
133                 zos.putArchiveEntry(txtEntry);
134                 zos.write(txtBytes);
135                 zos.closeArchiveEntry();
136
137                 // cleanup
138                 zos.finish();
139                 zos.close();
140                 os.flush();
141             } else {
142                 // unix: download a tar.gz file with pt.py set with execute permissions
143                 response.setHeader("Content-Disposition", "attachment; filename=\"pt.tar.gz\"");
144
145                 OutputStream os = response.getOutputStream();
146                 CompressorOutputStream cos = new CompressorStreamFactory().createCompressorOutputStream(CompressorStreamFactory.GZIP, os);
147                 TarArchiveOutputStream tos = new TarArchiveOutputStream(cos);
148                 tos.setAddPaxHeadersForNonAsciiNames(true);
149                 tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
150
151                 // add the Python script
152                 TarArchiveEntry pyEntry = new TarArchiveEntry("pt");
153                 pyEntry.setMode(FileMode.EXECUTABLE_FILE.getBits());
154                 pyEntry.setModTime(lastModified);
155                 pyEntry.setSize(pyBytes.length);
156                 tos.putArchiveEntry(pyEntry);
157                 tos.write(pyBytes);
158                 tos.closeArchiveEntry();
159
160                 // add a brief readme
161                 byte [] txtBytes = readAll(getClass().getResourceAsStream("/pt.txt"));
162                 TarArchiveEntry txtEntry = new TarArchiveEntry("README");
163                 txtEntry.setMode(FileMode.REGULAR_FILE.getBits());
164                 txtEntry.setModTime(lastModified);
165                 txtEntry.setSize(txtBytes.length);
166                 tos.putArchiveEntry(txtEntry);
167                 tos.write(txtBytes);
168                 tos.closeArchiveEntry();
169
170                 // cleanup
171                 tos.finish();
172                 tos.close();
173                 cos.close();
174                 os.flush();
175             }
176         } catch (Exception e) {
177             e.printStackTrace();
178         }
179     }
180
181     byte [] readAll(InputStream is) {
182         ByteArrayOutputStream os = new ByteArrayOutputStream();
183         try {
184             byte [] buffer = new byte[4096];
185             int len = 0;
186             while ((len = is.read(buffer)) > -1) {
187                 os.write(buffer, 0, len);
188             }
189             return os.toByteArray();
190         } catch (IOException e) {
191             e.printStackTrace();
192         } finally {
193             try {
194                 os.close();
195                 is.close();
196             } catch (Exception e) {
197                 // ignore
198             }
199         }
200         return new byte[0];
201     }
202 }