• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / httpunit / 755

14 Feb 2026 07:14PM UTC coverage: 80.526%. Remained the same
755

push

github

hazendaz
[ci] Fix badge

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

8245 of 10124 relevant lines covered (81.44%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.57
/src/main/java/com/meterware/pseudoserver/ReceivedHttpMessage.java
1
/*
2
 * SPDX-License-Identifier: MIT
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2000-2026 Russell Gold
6
 * Copyright 2021-2000 hazendaz
7
 */
8
package com.meterware.pseudoserver;
9

10
import java.io.ByteArrayInputStream;
11
import java.io.ByteArrayOutputStream;
12
import java.io.IOException;
13
import java.io.InputStream;
14
import java.io.InputStreamReader;
15
import java.io.Reader;
16
import java.util.Enumeration;
17
import java.util.Hashtable;
18

19
/**
20
 * The Class ReceivedHttpMessage.
21
 */
22
abstract class ReceivedHttpMessage {
23

24
    /** The Constant CR. */
25
    private static final int CR = 13;
26

27
    /** The Constant LF. */
28
    private static final int LF = 10;
29

30
    /** The reader. */
31
    private Reader _reader;
32

33
    /** The headers. */
34
    private Hashtable _headers = new Hashtable<>();
1✔
35

36
    /** The request body. */
37
    private byte[] _requestBody;
38

39
    /**
40
     * Instantiates a new received http message.
41
     *
42
     * @param inputStream
43
     *            the input stream
44
     *
45
     * @throws IOException
46
     *             Signals that an I/O exception has occurred.
47
     */
48
    ReceivedHttpMessage(InputStream inputStream) throws IOException {
1✔
49
        interpretMessageHeader(readHeaderLine(inputStream));
1✔
50
        readHeaders(inputStream);
1✔
51
        readMessageBody(inputStream);
1✔
52
    }
1✔
53

54
    @Override
55
    public String toString() {
56
        StringBuilder sb = new StringBuilder(getClassName()).append("[ ");
1✔
57
        appendMessageHeader(sb);
1✔
58
        sb.append("\n");
1✔
59
        for (Enumeration e = _headers.keys(); e.hasMoreElements();) {
1✔
60
            Object key = e.nextElement();
1✔
61
            sb.append("      ").append(key).append(": ").append(_headers.get(key)).append("\n");
1✔
62
        }
1✔
63
        sb.append("   body contains ").append(getBody().length).append(" byte(s)]");
1✔
64
        return sb.toString();
1✔
65
    }
66

67
    /**
68
     * Read header line.
69
     *
70
     * @param inputStream
71
     *            the input stream
72
     *
73
     * @return the string
74
     *
75
     * @throws IOException
76
     *             Signals that an I/O exception has occurred.
77
     */
78
    private String readHeaderLine(InputStream inputStream) throws IOException {
79
        return new String(readDelimitedChunk(inputStream));
1✔
80
    }
81

82
    /**
83
     * Read delimited chunk.
84
     *
85
     * @param inputStream
86
     *            the input stream
87
     *
88
     * @return the byte[]
89
     *
90
     * @throws IOException
91
     *             Signals that an I/O exception has occurred.
92
     */
93
    private byte[] readDelimitedChunk(InputStream inputStream) throws IOException {
94
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
1✔
95
        int b = inputStream.read();
1✔
96
        while (b != CR) {
1✔
97
            baos.write(b);
1✔
98
            b = inputStream.read();
1✔
99
        }
100

101
        b = inputStream.read();
1✔
102
        if (b != LF) {
1!
103
            throw new IOException("Bad header line termination: " + b);
×
104
        }
105
        return baos.toByteArray();
1✔
106
    }
107

108
    /**
109
     * Append contents.
110
     *
111
     * @param sb
112
     *            the sb
113
     */
114
    void appendContents(StringBuilder sb) {
115
        for (Enumeration e = _headers.keys(); e.hasMoreElements();) {
×
116
            Object key = e.nextElement();
×
117
            sb.append("      ").append(key).append(": ").append(_headers.get(key)).append("\n");
×
118
        }
×
119
        sb.append("   body contains ").append(getBody().length).append(" byte(s)");
×
120
    }
×
121

122
    /**
123
     * Gets the reader.
124
     *
125
     * @return the reader
126
     */
127
    Reader getReader() {
128
        return _reader;
×
129
    }
130

131
    /**
132
     * Gets the header.
133
     *
134
     * @param name
135
     *            the name
136
     *
137
     * @return the header
138
     */
139
    String getHeader(String name) {
140
        return (String) _headers.get(name.toUpperCase());
1✔
141
    }
142

143
    /**
144
     * Gets the body.
145
     *
146
     * @return the body
147
     */
148
    byte[] getBody() {
149
        return _requestBody;
1✔
150
    }
151

152
    /**
153
     * Read message body.
154
     *
155
     * @param inputStream
156
     *            the input stream
157
     *
158
     * @throws IOException
159
     *             Signals that an I/O exception has occurred.
160
     */
161
    private void readMessageBody(InputStream inputStream) throws IOException {
162
        if ("chunked".equalsIgnoreCase(getHeader("Transfer-Encoding"))) {
1✔
163
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
1✔
164
            while (getNextChunkLength(inputStream) > 0) {
1✔
165
                baos.write(readDelimitedChunk(inputStream));
1✔
166
            }
167
            flushChunkTrailer(inputStream);
1✔
168
            _requestBody = baos.toByteArray();
1✔
169
        } else {
1✔
170
            int totalExpected = getContentLength();
1✔
171
            ByteArrayOutputStream baos = new ByteArrayOutputStream(totalExpected);
1✔
172
            byte[] buffer = new byte[1024];
1✔
173
            int total = 0;
1✔
174
            int count = -1;
1✔
175
            while (total < totalExpected && (count = inputStream.read(buffer)) != -1) {
1!
176
                baos.write(buffer, 0, count);
1✔
177
                total += count;
1✔
178
            }
179
            baos.flush();
1✔
180
            _requestBody = baos.toByteArray();
1✔
181
        }
182
        _reader = new InputStreamReader(new ByteArrayInputStream(_requestBody));
1✔
183
    }
1✔
184

185
    /**
186
     * Flush chunk trailer.
187
     *
188
     * @param inputStream
189
     *            the input stream
190
     *
191
     * @throws IOException
192
     *             Signals that an I/O exception has occurred.
193
     */
194
    private void flushChunkTrailer(InputStream inputStream) throws IOException {
195
        byte[] line;
196
        do {
197
            line = readDelimitedChunk(inputStream);
1✔
198
        } while (line.length > 0);
1!
199
    }
1✔
200

201
    /**
202
     * Gets the next chunk length.
203
     *
204
     * @param inputStream
205
     *            the input stream
206
     *
207
     * @return the next chunk length
208
     *
209
     * @throws IOException
210
     *             Signals that an I/O exception has occurred.
211
     */
212
    private int getNextChunkLength(InputStream inputStream) throws IOException {
213
        try {
214
            return Integer.parseInt(readHeaderLine(inputStream), 16);
1✔
215
        } catch (NumberFormatException e) {
×
216
            throw new IOException("Unabled to read chunk length: " + e);
×
217
        }
218
    }
219

220
    /**
221
     * Gets the content length.
222
     *
223
     * @return the content length
224
     */
225
    private int getContentLength() {
226
        try {
227
            return Integer.parseInt(getHeader("Content-Length"));
1✔
228
        } catch (NumberFormatException e) {
1✔
229
            return 0;
1✔
230
        }
231
    }
232

233
    /**
234
     * Read headers.
235
     *
236
     * @param inputStream
237
     *            the input stream
238
     *
239
     * @throws IOException
240
     *             Signals that an I/O exception has occurred.
241
     */
242
    private void readHeaders(InputStream inputStream) throws IOException {
243
        String lastHeader = null;
1✔
244

245
        String header = readHeaderLine(inputStream);
1✔
246
        while (header.length() > 0) {
1✔
247
            if (header.charAt(0) <= ' ') {
1!
248
                if (lastHeader == null) {
×
249
                    continue;
×
250
                }
251
                _headers.put(lastHeader, _headers.get(lastHeader) + header.trim());
×
252
            } else {
253
                lastHeader = header.substring(0, header.indexOf(':')).toUpperCase();
1✔
254
                _headers.put(lastHeader, header.substring(header.indexOf(':') + 1).trim());
1✔
255
            }
256
            header = readHeaderLine(inputStream);
1✔
257
        }
258
    }
1✔
259

260
    /**
261
     * Gets the class name.
262
     *
263
     * @return the class name
264
     */
265
    private String getClassName() {
266
        return getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1);
1✔
267
    }
268

269
    /**
270
     * Append message header.
271
     *
272
     * @param sb
273
     *            the sb
274
     */
275
    abstract void appendMessageHeader(StringBuilder sb);
276

277
    /**
278
     * Interpret message header.
279
     *
280
     * @param messageHeader
281
     *            the message header
282
     */
283
    abstract void interpretMessageHeader(String messageHeader);
284

285
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc