View Javadoc
1   /*
2    * SPDX-License-Identifier: MIT
3    * See LICENSE file for details.
4    *
5    * Copyright 2010-2026 The Waffle Project Contributors: https://github.com/Waffle/waffle/graphs/contributors
6    */
7   package waffle.mock.http;
8   
9   import jakarta.servlet.ServletOutputStream;
10  import jakarta.servlet.WriteListener;
11  import jakarta.servlet.http.HttpServletResponse;
12  import jakarta.servlet.http.HttpServletResponseWrapper;
13  
14  import java.io.ByteArrayOutputStream;
15  import java.io.IOException;
16  import java.io.OutputStreamWriter;
17  import java.io.PrintWriter;
18  import java.nio.charset.StandardCharsets;
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.mockito.Mockito;
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  
28  /**
29   * The Class SimpleHttpResponse.
30   */
31  public class SimpleHttpResponse extends HttpServletResponseWrapper {
32  
33      /** The Constant LOGGER. */
34      private static final Logger LOGGER = LoggerFactory.getLogger(SimpleHttpResponse.class);
35  
36      /** The status. */
37      private int status = 500;
38  
39      /** The headers. */
40      private final Map<String, List<String>> headers = new HashMap<>();
41  
42      /** The bytes. */
43      private final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
44  
45      /** The out. */
46      private final ServletOutputStream out = new ServletOutputStream() {
47          @Override
48          public void write(final int b) {
49              SimpleHttpResponse.this.bytes.write(b);
50          }
51  
52          @Override
53          public boolean isReady() {
54              return false;
55          }
56  
57          @Override
58          public void setWriteListener(final WriteListener writeListener) {
59              // Not used
60          }
61      };
62  
63      /** The writer. */
64      private final PrintWriter writer = new PrintWriter(new OutputStreamWriter(this.bytes, StandardCharsets.UTF_8),
65              true);
66  
67      /**
68       * Instantiates a new simple http response.
69       */
70      public SimpleHttpResponse() {
71          super(Mockito.mock(HttpServletResponse.class));
72      }
73  
74      /**
75       * Gets the status.
76       *
77       * @return the status
78       */
79      @Override
80      public int getStatus() {
81          return this.status;
82      }
83  
84      @Override
85      public void addHeader(final String headerName, final String headerValue) {
86          List<String> current = this.headers.get(headerName);
87          if (current == null) {
88              current = new ArrayList<>();
89          }
90          current.add(headerValue);
91          this.headers.put(headerName, current);
92      }
93  
94      @Override
95      public void setHeader(final String headerName, final String headerValue) {
96          List<String> current = this.headers.get(headerName);
97          if (current == null) {
98              current = new ArrayList<>();
99          } else {
100             current.clear();
101         }
102         current.add(headerValue);
103         this.headers.put(headerName, current);
104     }
105 
106     @Override
107     public void setStatus(final int value) {
108         this.status = value;
109     }
110 
111     /**
112      * Gets the status string.
113      *
114      * @return the status string
115      */
116     public String getStatusString() {
117         if (this.status == 401) {
118             return "Unauthorized";
119         }
120         return "Unknown";
121     }
122 
123     @Override
124     public void flushBuffer() {
125         SimpleHttpResponse.LOGGER.info("{}: {}", Integer.valueOf(this.status), this.getStatusString());
126         for (final Map.Entry<String, List<String>> header : this.headers.entrySet()) {
127             for (final String headerValue : header.getValue()) {
128                 SimpleHttpResponse.LOGGER.info("{}: {}", header, headerValue);
129             }
130         }
131     }
132 
133     /**
134      * Use this for testing the number of headers.
135      *
136      * @return int header name size.
137      */
138     public int getHeaderNamesSize() {
139         return this.headers.size();
140     }
141 
142     /**
143      * Gets the header values.
144      *
145      * @param headerName
146      *            the header name
147      *
148      * @return the header values
149      */
150     public String[] getHeaderValues(final String headerName) {
151         final List<String> headerValues = this.headers.get(headerName);
152         return headerValues == null ? null : headerValues.toArray(new String[0]);
153     }
154 
155     /**
156      * Gets the header.
157      *
158      * @param headerName
159      *            the header name
160      *
161      * @return the header
162      */
163     @Override
164     public String getHeader(final String headerName) {
165         final List<String> headerValues = this.headers.get(headerName);
166         return headerValues == null ? null : String.join(", ", headerValues);
167     }
168 
169     @Override
170     public void sendError(final int rc, final String message) {
171         this.status = rc;
172     }
173 
174     @Override
175     public void sendError(final int rc) {
176         this.status = rc;
177     }
178 
179     @Override
180     public PrintWriter getWriter() {
181         return this.writer;
182     }
183 
184     @Override
185     public ServletOutputStream getOutputStream() throws IOException {
186         return this.out;
187     }
188 
189     /**
190      * Gets the output text.
191      *
192      * @return the output text
193      */
194     public String getOutputText() {
195         this.writer.flush();
196         return this.bytes.toString(StandardCharsets.UTF_8);
197     }
198 }