~ubuntu-branches/ubuntu/saucy/jenkins/saucy

« back to all changes in this revision

Viewing changes to core/src/main/groovy/jenkins/util/MarkFindingOutputStream.java

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-01-10 09:50:50 UTC
  • mfrom: (5.1.10 experimental)
  • Revision ID: package-import@ubuntu.com-20130110095050-kj8xuw20gcfh62k3
Tags: 1.480.2+dfsg-1~exp1
* New upstream release (Closes: #696816, #697617):
  - d/control: Added new BD on libjbcrypt-java.
  - d/control: Versioned BD jenkins-winstone >= 0.9.10-jenkins-40.
  - d/control: Versioned BD jenkins-trilead-ssh2 >= 214-jenkins-1.
  - Fixes the following security vulnerabilities:
    CVE-2012-6072, CVE-2012-6073, CVE-2012-6072, CVE-2013-0158.
* Tidied lintian warnings.
* Bumped Standards-Version: 3.9.4, no changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package jenkins.util;
2
 
 
3
 
import java.io.IOException;
4
 
import java.io.OutputStream;
5
 
import java.io.UnsupportedEncodingException;
6
 
 
7
 
/**
8
 
 * Filtering {@link OutputStream} that looks for {@link #MARK} in the output stream and notifies the callback.
9
 
 *
10
 
 * The mark itself will be removed from the stream.
11
 
 * 
12
 
 * @author Kohsuke Kawaguchi
13
 
 * @since 1.458
14
 
 */
15
 
public abstract class MarkFindingOutputStream extends OutputStream {
16
 
    private final OutputStream base;
17
 
 
18
 
    public MarkFindingOutputStream(OutputStream base) {
19
 
        this.base = base;
20
 
    }
21
 
 
22
 
    /**
23
 
     * Position in {@link #MARK} if we are currently suspecting a match.
24
 
     */
25
 
    private int match = 0;
26
 
 
27
 
    public synchronized void write(int b) throws IOException {
28
 
        if (MBYTES[match] == b) {// another byte matched. Good. Keep going...
29
 
            match++;
30
 
            if (match == MBYTES.length) {
31
 
                // don't send MARK to the output, but instead notify the callback
32
 
                onMarkFound();
33
 
                match = 0;
34
 
            }
35
 
        } else {
36
 
            if (match > 0) {
37
 
                // only matched partially. send the partial match that we held off down the pipe
38
 
                base.write(MBYTES, 0, match);
39
 
                match = 0;
40
 
 
41
 
                // this might match the first byte in MARK, so retry.
42
 
                write(b);
43
 
            } else {
44
 
                base.write(b);
45
 
            }
46
 
        }
47
 
    }
48
 
 
49
 
    public void write(byte b[], int off, int len) throws IOException {
50
 
        final int start = off; 
51
 
        final int end = off + len;
52
 
        for (int i=off; i<end; ) {
53
 
            if (MBYTES[match] == b[i]) {// another byte matched. Good. Keep going...
54
 
                match++;
55
 
                i++;
56
 
                if (match == MBYTES.length) {
57
 
                    base.write(b,off,i-off-MBYTES.length);    // flush the portion up to MARK
58
 
                    // don't send MARK to the output, but instead notify the callback
59
 
                    onMarkFound();
60
 
                    match = 0;
61
 
                    off = i;
62
 
                    len = end-i;
63
 
                }
64
 
            } else {
65
 
                if (match > 0) {
66
 
                    // only matched partially.
67
 
                    // if a part of the partial match spans into the previous write, we need to fake that write.
68
 
                    int extra = match-(i-start);
69
 
                    if (extra>0) {
70
 
                        base.write(MBYTES,0,extra);
71
 
                    }
72
 
                    match = 0;
73
 
 
74
 
                    // this b[i] might be a fast byte in MARK, so we'll retry
75
 
                } else {
76
 
                    // irrelevant byte.
77
 
                    i++;
78
 
                }
79
 
            }
80
 
 
81
 
        }
82
 
 
83
 
        // if we are partially matching, can't send that portion yet.
84
 
        if (len-match>0)
85
 
            base.write(b, off, len-match);
86
 
    }
87
 
 
88
 
    public void flush() throws IOException {
89
 
        flushPartialMatch();
90
 
        base.flush();
91
 
    }
92
 
 
93
 
    public void close() throws IOException {
94
 
        flushPartialMatch();
95
 
        base.close();
96
 
    }
97
 
 
98
 
    private void flushPartialMatch() throws IOException {
99
 
        if (match>0) {
100
 
            base.write(MBYTES,0,match);
101
 
            match = 0;
102
 
        }
103
 
    }
104
 
 
105
 
    protected  abstract void onMarkFound();
106
 
 
107
 
    // having a new line in the end makes it work better with line-buffering transformation
108
 
    public static final String MARK = "[Jenkins:SYNC-MARK]\n";
109
 
    private static final byte[] MBYTES = toUTF8(MARK);
110
 
    
111
 
    private static byte[] toUTF8(String s) {
112
 
        try {
113
 
            return s.getBytes("UTF-8");
114
 
        } catch (UnsupportedEncodingException e) {
115
 
            throw new AssertionError(e);
116
 
        }
117
 
    }
118
 
}