James Moger
2014-07-03 efdb2b3d0c6f03a9aac9e65892cbc8ff755f246f
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
25 import javax.servlet.ServletException;
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.http.HttpServletResponse;
28
29 import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
30 import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
31 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
32 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
33 import org.apache.commons.compress.compressors.CompressorOutputStream;
34 import org.apache.commons.compress.compressors.CompressorStreamFactory;
35 import org.eclipse.jgit.lib.FileMode;
36
37 import com.gitblit.dagger.DaggerServlet;
38 import com.gitblit.manager.IRuntimeManager;
39
40 import dagger.ObjectGraph;
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  */
50 public class PtServlet extends DaggerServlet {
51
52     private static final long serialVersionUID = 1L;
53
54     private static final long lastModified = System.currentTimeMillis();
55
56     private IRuntimeManager runtimeManager;
57
58     @Override
59     protected void inject(ObjectGraph dagger) {
60         this.runtimeManager = dagger.get(IRuntimeManager.class);
61     }
62
63     @Override
64     protected long getLastModified(HttpServletRequest req) {
65         File file = runtimeManager.getFileOrFolder("tickets.pt", "${baseFolder}/pt.py");
66         if (file.exists()) {
67             return Math.max(lastModified, file.lastModified());
68         } else {
69             return lastModified;
70         }
71     }
72
73     @Override
74     protected void doGet(HttpServletRequest request, HttpServletResponse response)
75             throws ServletException, IOException {
76         try {
77             response.setContentType("application/octet-stream");
78             response.setDateHeader("Last-Modified", lastModified);
79             response.setHeader("Cache-Control", "none");
80             response.setHeader("Pragma", "no-cache");
81             response.setDateHeader("Expires", 0);
82
83             boolean windows = false;
84             try {
85                 String useragent = request.getHeader("user-agent").toString();
86                 windows = useragent.toLowerCase().contains("windows");
87             } catch (Exception e) {
88             }
89
90             byte[] pyBytes;
91             File file = runtimeManager.getFileOrFolder("tickets.pt", "${baseFolder}/pt.py");
92             if (file.exists()) {
93                 // custom script
94                 pyBytes = readAll(new FileInputStream(file));
95             } else {
96                 // default script
97                 pyBytes = readAll(getClass().getResourceAsStream("/pt.py"));
98             }
99
100             if (windows) {
101                 // windows: download zip file with pt.py and pt.cmd
102                 response.setHeader("Content-Disposition", "attachment; filename=\"pt.zip\"");
103
104                 OutputStream os = response.getOutputStream();
105                 ZipArchiveOutputStream zos = new ZipArchiveOutputStream(os);
106
107                 // add the Python script
108                 ZipArchiveEntry pyEntry = new ZipArchiveEntry("pt.py");
109                 pyEntry.setSize(pyBytes.length);
110                 pyEntry.setUnixMode(FileMode.EXECUTABLE_FILE.getBits());
111                 pyEntry.setTime(lastModified);
112                 zos.putArchiveEntry(pyEntry);
113                 zos.write(pyBytes);
114                 zos.closeArchiveEntry();
115
116                 // add a Python launch cmd file
117                 byte [] cmdBytes = readAll(getClass().getResourceAsStream("/pt.cmd"));
118                 ZipArchiveEntry cmdEntry = new ZipArchiveEntry("pt.cmd");
119                 cmdEntry.setSize(cmdBytes.length);
120                 cmdEntry.setUnixMode(FileMode.REGULAR_FILE.getBits());
121                 cmdEntry.setTime(lastModified);
122                 zos.putArchiveEntry(cmdEntry);
123                 zos.write(cmdBytes);
124                 zos.closeArchiveEntry();
125
126                 // add a brief readme
127                 byte [] txtBytes = readAll(getClass().getResourceAsStream("/pt.txt"));
128                 ZipArchiveEntry txtEntry = new ZipArchiveEntry("readme.txt");
129                 txtEntry.setSize(txtBytes.length);
130                 txtEntry.setUnixMode(FileMode.REGULAR_FILE.getBits());
131                 txtEntry.setTime(lastModified);
132                 zos.putArchiveEntry(txtEntry);
133                 zos.write(txtBytes);
134                 zos.closeArchiveEntry();
135
136                 // cleanup
137                 zos.finish();
138                 zos.close();
139                 os.flush();
140             } else {
141                 // unix: download a tar.gz file with pt.py set with execute permissions
142                 response.setHeader("Content-Disposition", "attachment; filename=\"pt.tar.gz\"");
143
144                 OutputStream os = response.getOutputStream();
145                 CompressorOutputStream cos = new CompressorStreamFactory().createCompressorOutputStream(CompressorStreamFactory.GZIP, os);
146                 TarArchiveOutputStream tos = new TarArchiveOutputStream(cos);
147                 tos.setAddPaxHeadersForNonAsciiNames(true);
148                 tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
149
150                 // add the Python script
151                 TarArchiveEntry pyEntry = new TarArchiveEntry("pt");
152                 pyEntry.setMode(FileMode.EXECUTABLE_FILE.getBits());
153                 pyEntry.setModTime(lastModified);
154                 pyEntry.setSize(pyBytes.length);
155                 tos.putArchiveEntry(pyEntry);
156                 tos.write(pyBytes);
157                 tos.closeArchiveEntry();
158
159                 // add a brief readme
160                 byte [] txtBytes = readAll(getClass().getResourceAsStream("/pt.txt"));
161                 TarArchiveEntry txtEntry = new TarArchiveEntry("README");
162                 txtEntry.setMode(FileMode.REGULAR_FILE.getBits());
163                 txtEntry.setModTime(lastModified);
164                 txtEntry.setSize(txtBytes.length);
165                 tos.putArchiveEntry(txtEntry);
166                 tos.write(txtBytes);
167                 tos.closeArchiveEntry();
168
169                 // cleanup
170                 tos.finish();
171                 tos.close();
172                 cos.close();
173                 os.flush();
174             }
175         } catch (Exception e) {
176             e.printStackTrace();
177         }
178     }
179
180     byte [] readAll(InputStream is) {
181         ByteArrayOutputStream os = new ByteArrayOutputStream();
182         try {
183             byte [] buffer = new byte[4096];
184             int len = 0;
185             while ((len = is.read(buffer)) > -1) {
186                 os.write(buffer, 0, len);
187             }
188             return os.toByteArray();
189         } catch (IOException e) {
190             e.printStackTrace();
191         } finally {
192             try {
193                 os.close();
194                 is.close();
195             } catch (Exception e) {
196                 // ignore
197             }
198         }
199         return new byte[0];
200     }
201 }