File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\console\AnnotatedLargeText.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2010, Sun Microsystems, Inc.
5 *
6 * Copyright (c) 2012, Martin Schroeder, Intel Mobile Communications GmbH
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26 package hudson.console;
27
28 import com.trilead.ssh2.crypto.Base64;
29 import jenkins.model.Jenkins;
30 import hudson.remoting.ObjectInputStreamEx;
31 import hudson.util.IOException2;
32 import hudson.util.Secret;
33 import hudson.util.TimeUnit2;
34 import jenkins.security.CryptoConfidentialKey;
35 import org.apache.commons.io.output.ByteArrayOutputStream;
36 import org.kohsuke.stapler.Stapler;
37 import org.kohsuke.stapler.StaplerRequest;
38 import org.kohsuke.stapler.StaplerResponse;
39 import org.kohsuke.stapler.framework.io.ByteBuffer;
40 import org.kohsuke.stapler.framework.io.LargeText;
41
42 import javax.crypto.Cipher;
43 import javax.crypto.CipherInputStream;
44 import javax.crypto.CipherOutputStream;
45 import java.io.ByteArrayInputStream;
46 import java.io.File;
47 import java.io.IOException;
48 import java.io.ObjectInputStream;
49 import java.io.ObjectOutputStream;
50 import java.io.OutputStream;
51 import java.io.Writer;
52 import java.nio.charset.Charset;
53 import java.security.GeneralSecurityException;
54 import java.util.zip.GZIPInputStream;
55 import java.util.zip.GZIPOutputStream;
56
57 import static java.lang.Math.abs;
58
59 /**
60 * Extension to {@link LargeText} that handles annotations by {@link ConsoleAnnotator}.
61 *
62 * <p>
63 * In addition to run each line through {@link ConsoleAnnotationOutputStream} for adding markup,
64 * this class persists {@link ConsoleAnnotator} into a byte sequence and send it to the client
65 * as an HTTP header. The client JavaScript sends it back next time it fetches the following output.
66 *
67 * <p>
68 * The serialized {@link ConsoleAnnotator} is encrypted to avoid malicious clients from instantiating
69 * arbitrary {@link ConsoleAnnotator}s.
70 *
71 * @param <T>
72 * Context type.
73 * @author Kohsuke Kawaguchi
74 * @since 1.349
75 */
76 public class AnnotatedLargeText<T> extends LargeText {
77 /**
78 * Can be null.
79 */
80 private T context;
81
82 public AnnotatedLargeText(File file, Charset charset, boolean completed, T context) {
83 super(file, charset, completed, true);
84 this.context = context;
85 }
86
87 public AnnotatedLargeText(ByteBuffer memory, Charset charset, boolean completed, T context) {
88 super(memory, charset, completed);
89 this.context = context;
90 }
91
92 public void doProgressiveHtml(StaplerRequest req, StaplerResponse rsp) throws IOException {
93 req.setAttribute("html",true);
94 doProgressText(req,rsp);
95 }
96
97 /**
98 * Aliasing what I think was a wrong name in {@link LargeText}
99 */
100 public void doProgressiveText(StaplerRequest req, StaplerResponse rsp) throws IOException {
101 doProgressText(req,rsp);
102 }
103
104 /**
105 * For reusing code between text/html and text/plain, we run them both through the same code path
106 * and use this request attribute to differentiate.
107 */
108 private boolean isHtml() {
109 StaplerRequest req = Stapler.getCurrentRequest();
110 return req!=null && req.getAttribute("html")!=null;
111 }
112
113 @Override
114 protected void setContentType(StaplerResponse rsp) {
115 rsp.setContentType(isHtml() ? "text/html;charset=UTF-8" : "text/plain;charset=UTF-8");
116 }
117
118 private ConsoleAnnotator createAnnotator(StaplerRequest req) throws IOException {
119 try {
120 String base64 = req!=null ? req.getHeader("X-ConsoleAnnotator") : null;
121 if (base64!=null) {
122 Cipher sym = PASSING_ANNOTATOR.decrypt();
123
124 ObjectInputStream ois = new ObjectInputStreamEx(new GZIPInputStream(
125 new CipherInputStream(new ByteArrayInputStream(Base64.decode(base64.toCharArray())),sym)),
126 Jenkins.getInstance().pluginManager.uberClassLoader);
127 try {
128 long timestamp = ois.readLong();
129 if (TimeUnit2.HOURS.toMillis(1) > abs(System.currentTimeMillis()-timestamp))
130 // don't deserialize something too old to prevent a replay attack
131 return (ConsoleAnnotator)ois.readObject();
132 } finally {
133 ois.close();
134 }
135 }
136 } catch (ClassNotFoundException e) {
137 throw new IOException2(e);
138 }
139 // start from scratch
140 return ConsoleAnnotator.initial(context==null ? null : context.getClass());
141 }
142
143 @Override
144 public long writeLogTo(long start, Writer w) throws IOException {
145 if (isHtml())
146 return writeHtmlTo(start, w);
147 else
148 return super.writeLogTo(start,w);
149 }
150
151 @Override
152 public long writeLogTo(long start, OutputStream out) throws IOException {
153 return super.writeLogTo(start, new PlainTextConsoleOutputStream(out));
154 }
155
156 public long writeHtmlTo(long start, Writer w) throws IOException {
157 ConsoleAnnotationOutputStream caw = new ConsoleAnnotationOutputStream(
158 w, createAnnotator(Stapler.getCurrentRequest()), context, charset);
159 long r = super.writeLogTo(start,caw);
160
161 ByteArrayOutputStream baos = new ByteArrayOutputStream();
162 Cipher sym = PASSING_ANNOTATOR.encrypt();
163 ObjectOutputStream oos = new ObjectOutputStream(new GZIPOutputStream(new CipherOutputStream(baos,sym)));
164 oos.writeLong(System.currentTimeMillis()); // send timestamp to prevent a replay attack
165 oos.writeObject(caw.getConsoleAnnotator());
166 oos.close();
167 StaplerResponse rsp = Stapler.getCurrentResponse();
168 if (rsp!=null)
169 rsp.setHeader("X-ConsoleAnnotator", new String(Base64.encode(baos.toByteArray())));
170 return r;
171 }
172
173 /**
174 * Used for sending the state of ConsoleAnnotator to the client, because we are deserializing this object later.
175 */
176 private static final CryptoConfidentialKey PASSING_ANNOTATOR = new CryptoConfidentialKey(AnnotatedLargeText.class,"consoleAnnotator");
177 }
178