View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.core5.http.message;
29  
30  import java.nio.charset.StandardCharsets;
31  import java.util.ArrayList;
32  import java.util.Arrays;
33  import java.util.Collections;
34  import java.util.LinkedHashSet;
35  import java.util.List;
36  import java.util.Set;
37  
38  import org.apache.hc.core5.http.ContentType;
39  import org.apache.hc.core5.http.Header;
40  import org.apache.hc.core5.http.HeaderElement;
41  import org.apache.hc.core5.http.HttpEntity;
42  import org.apache.hc.core5.http.HttpHeaders;
43  import org.apache.hc.core5.http.HttpMessage;
44  import org.apache.hc.core5.http.HttpResponse;
45  import org.apache.hc.core5.http.HttpStatus;
46  import org.apache.hc.core5.http.NameValuePair;
47  import org.apache.hc.core5.http.io.entity.HttpEntities;
48  import org.apache.hc.core5.http.support.BasicResponseBuilder;
49  import org.apache.hc.core5.util.CharArrayBuffer;
50  import org.junit.jupiter.api.Assertions;
51  import org.junit.jupiter.api.Test;
52  
53  public class TestMessageSupport {
54  
55      private static Set<String> makeSet(final String... tokens) {
56          if (tokens == null) {
57              return null;
58          }
59          final Set<String> set = new LinkedHashSet<>();
60          Collections.addAll(set, tokens);
61          return set;
62      }
63  
64      @Test
65      public void testTokenSetFormatting() throws Exception {
66          final Header header = MessageSupport.header(HttpHeaders.TRAILER, makeSet("z", "b", "a"));
67          Assertions.assertNotNull(header);
68          Assertions.assertEquals("z, b, a", header.getValue());
69      }
70  
71      @Test
72      public void testTokenListFormatting() throws Exception {
73          final Header header = MessageSupport.headerOfTokens(HttpHeaders.TRAILER, Arrays.asList("z", "b", "a", "a"));
74          Assertions.assertNotNull(header);
75          Assertions.assertEquals("z, b, a, a", header.getValue());
76      }
77  
78      @Test
79      public void testTokenSetFormattingSameName() throws Exception {
80          final Header header = MessageSupport.header(HttpHeaders.TRAILER, makeSet("a", "a", "a"));
81          Assertions.assertNotNull(header);
82          Assertions.assertEquals("a", header.getValue());
83      }
84  
85      @Test
86      public void testTokenListFormattingSameName() throws Exception {
87          final Header header = MessageSupport.header(HttpHeaders.TRAILER, "a", "a", "a");
88          Assertions.assertNotNull(header);
89          Assertions.assertEquals("a, a, a", header.getValue());
90      }
91  
92      @Test
93      public void testParseTokensWithConsumer() throws Exception {
94          final String s = "a, b, c, c";
95          final ParserCursor cursor = new ParserCursor(0, s.length());
96          final List<String> tokens = new ArrayList<>();
97          MessageSupport.parseTokens(s, cursor, tokens::add);
98          Assertions.assertEquals(Arrays.asList("a", "b", "c", "c"), tokens);
99      }
100 
101     @Test
102     public void testParseTokenHeaderWithConsumer() throws Exception {
103         final Header header = new BasicHeader(HttpHeaders.TRAILER, "a, b, c, c");
104         final List<String> tokens = new ArrayList<>();
105         MessageSupport.parseTokens(header, tokens::add);
106         Assertions.assertEquals(Arrays.asList("a", "b", "c", "c"), tokens);
107     }
108 
109     @Test
110     public void testParseTokenBufferWithConsumer() throws Exception {
111         final CharArrayBuffer buf = new CharArrayBuffer(128);
112         buf.append("stuff: a, b, c, c");
113         final Header header = BufferedHeader.create(buf);
114         Assertions.assertEquals(makeSet("a", "b", "c", "c"), MessageSupport.parseTokens(header));
115     }
116 
117     @Test
118     public void testParseTokens() throws Exception {
119         final String s = "a, b, c, c";
120         final ParserCursor cursor = new ParserCursor(0, s.length());
121         Assertions.assertEquals(makeSet("a", "b", "c"), MessageSupport.parseTokens(s, cursor));
122     }
123 
124     @Test
125     public void testParseTokenHeader() throws Exception {
126         final Header header = new BasicHeader(HttpHeaders.TRAILER, "a, b, c, c");
127         Assertions.assertEquals(makeSet("a", "b", "c"), MessageSupport.parseTokens(header));
128     }
129 
130     @Test
131     public void testParseTokenBuffer() throws Exception {
132         final CharArrayBuffer buf = new CharArrayBuffer(128);
133         buf.append("stuff: a, b, c, c");
134         final Header header = BufferedHeader.create(buf);
135         Assertions.assertEquals(makeSet("a", "b", "c"), MessageSupport.parseTokens(header));
136     }
137 
138     @Test
139     public void testElementListFormatting() throws Exception {
140         final List<HeaderElement> elements = Arrays.asList(
141                 new BasicHeaderElement("name1", "value1", new BasicNameValuePair("param", "regular_stuff")),
142                 new BasicHeaderElement("name2", "value2", new BasicNameValuePair("param", "this\\that")),
143                 new BasicHeaderElement("name3", "value3", new BasicNameValuePair("param", "this,that")),
144                 new BasicHeaderElement("name4", "value4", new BasicNameValuePair("param", null)),
145                 new BasicHeaderElement("name5", null));
146 
147         final Header header = MessageSupport.headerOfElements("Some-header", elements);
148         Assertions.assertNotNull(header);
149         Assertions.assertEquals("name1=value1; param=regular_stuff, name2=value2; " +
150                 "param=\"this\\\\that\", name3=value3; param=\"this,that\", " +
151                 "name4=value4; param, name5", header.getValue());
152     }
153 
154     @Test
155     public void testElementArrayFormatting() throws Exception {
156         final HeaderElement[] elements = {
157                 new BasicHeaderElement("name1", "value1", new BasicNameValuePair("param", "regular_stuff")),
158                 new BasicHeaderElement("name2", "value2", new BasicNameValuePair("param", "this\\that")),
159                 new BasicHeaderElement("name3", "value3", new BasicNameValuePair("param", "this,that")),
160                 new BasicHeaderElement("name4", "value4", new BasicNameValuePair("param", null)),
161                 new BasicHeaderElement("name5", null)};
162 
163         final Header header = MessageSupport.header("Some-Header", elements);
164         Assertions.assertNotNull(header);
165         Assertions.assertEquals("name1=value1; param=regular_stuff, name2=value2; " +
166                 "param=\"this\\\\that\", name3=value3; param=\"this,that\", " +
167                 "name4=value4; param, name5", header.getValue());
168     }
169 
170     @Test
171     public void testParseElementsBufferWithConsumer() throws Exception {
172         final CharArrayBuffer buf = new CharArrayBuffer(64);
173         buf.append("name1 = value1; name2; name3=\"value3\" , name4=value4; " +
174                 "name5=value5, name6= ; name7 = value7; name8 = \" value8\"");
175         final List<HeaderElement> elements = new ArrayList<>();
176         final ParserCursor cursor = new ParserCursor(0, buf.length());
177         MessageSupport.parseElements(buf, cursor, elements::add);
178         // there are 3 elements
179         Assertions.assertEquals(3,elements.size());
180         // 1st element
181         Assertions.assertEquals("name1", elements.get(0).getName());
182         Assertions.assertEquals("value1", elements.get(0).getValue());
183         // 1st element has 2 getParameters()
184         Assertions.assertEquals(2, elements.get(0).getParameters().length);
185         Assertions.assertEquals("name2", elements.get(0).getParameters()[0].getName());
186         Assertions.assertNull(elements.get(0).getParameters()[0].getValue());
187         Assertions.assertEquals("name3", elements.get(0).getParameters()[1].getName());
188         Assertions.assertEquals("value3", elements.get(0).getParameters()[1].getValue());
189         // 2nd element
190         Assertions.assertEquals("name4", elements.get(1).getName());
191         Assertions.assertEquals("value4", elements.get(1).getValue());
192         // 2nd element has 1 parameter
193         Assertions.assertEquals(1, elements.get(1).getParameters().length);
194         Assertions.assertEquals("name5", elements.get(1).getParameters()[0].getName());
195         Assertions.assertEquals("value5", elements.get(1).getParameters()[0].getValue());
196         // 3rd element
197         Assertions.assertEquals("name6", elements.get(2).getName());
198         Assertions.assertEquals("", elements.get(2).getValue());
199         // 3rd element has 2 getParameters()
200         Assertions.assertEquals(2, elements.get(2).getParameters().length);
201         Assertions.assertEquals("name7", elements.get(2).getParameters()[0].getName());
202         Assertions.assertEquals("value7", elements.get(2).getParameters()[0].getValue());
203         Assertions.assertEquals("name8", elements.get(2).getParameters()[1].getName());
204         Assertions.assertEquals(" value8", elements.get(2).getParameters()[1].getValue());
205     }
206 
207     @Test
208     public void testParseElementsHeaderWithConsumer() throws Exception {
209         final Header header = new BasicHeader("Some-Header",
210                 "name1 = value1; name2; name3=\"value3\" , name4=value4; " +
211                 "name5=value5, name6= ; name7 = value7; name8 = \" value8\"");
212         final List<HeaderElement> elements = new ArrayList<>();
213         MessageSupport.parseElements(header, elements::add);
214         // there are 3 elements
215         Assertions.assertEquals(3,elements.size());
216         // 1st element
217         Assertions.assertEquals("name1", elements.get(0).getName());
218         Assertions.assertEquals("value1", elements.get(0).getValue());
219         // 1st element has 2 getParameters()
220         Assertions.assertEquals(2, elements.get(0).getParameters().length);
221         Assertions.assertEquals("name2", elements.get(0).getParameters()[0].getName());
222         Assertions.assertNull(elements.get(0).getParameters()[0].getValue());
223         Assertions.assertEquals("name3", elements.get(0).getParameters()[1].getName());
224         Assertions.assertEquals("value3", elements.get(0).getParameters()[1].getValue());
225         // 2nd element
226         Assertions.assertEquals("name4", elements.get(1).getName());
227         Assertions.assertEquals("value4", elements.get(1).getValue());
228         // 2nd element has 1 parameter
229         Assertions.assertEquals(1, elements.get(1).getParameters().length);
230         Assertions.assertEquals("name5", elements.get(1).getParameters()[0].getName());
231         Assertions.assertEquals("value5", elements.get(1).getParameters()[0].getValue());
232         // 3rd element
233         Assertions.assertEquals("name6", elements.get(2).getName());
234         Assertions.assertEquals("", elements.get(2).getValue());
235         // 3rd element has 2 getParameters()
236         Assertions.assertEquals(2, elements.get(2).getParameters().length);
237         Assertions.assertEquals("name7", elements.get(2).getParameters()[0].getName());
238         Assertions.assertEquals("value7", elements.get(2).getParameters()[0].getValue());
239         Assertions.assertEquals("name8", elements.get(2).getParameters()[1].getName());
240         Assertions.assertEquals(" value8", elements.get(2).getParameters()[1].getValue());
241     }
242 
243     @Test
244     public void testParseElementsHeader() throws Exception {
245         final Header header = new BasicHeader("Some-Header",
246                 "name1 = value1; name2; name3=\"value3\" , name4=value4; " +
247                         "name5=value5, name6= ; name7 = value7; name8 = \" value8\"");
248         final List<HeaderElement> elements = MessageSupport.parseElements(header);
249         // there are 3 elements
250         Assertions.assertEquals(3,elements.size());
251         // 1st element
252         Assertions.assertEquals("name1", elements.get(0).getName());
253         Assertions.assertEquals("value1", elements.get(0).getValue());
254         // 1st element has 2 getParameters()
255         Assertions.assertEquals(2, elements.get(0).getParameters().length);
256         Assertions.assertEquals("name2", elements.get(0).getParameters()[0].getName());
257         Assertions.assertNull(elements.get(0).getParameters()[0].getValue());
258         Assertions.assertEquals("name3", elements.get(0).getParameters()[1].getName());
259         Assertions.assertEquals("value3", elements.get(0).getParameters()[1].getValue());
260         // 2nd element
261         Assertions.assertEquals("name4", elements.get(1).getName());
262         Assertions.assertEquals("value4", elements.get(1).getValue());
263         // 2nd element has 1 parameter
264         Assertions.assertEquals(1, elements.get(1).getParameters().length);
265         Assertions.assertEquals("name5", elements.get(1).getParameters()[0].getName());
266         Assertions.assertEquals("value5", elements.get(1).getParameters()[0].getValue());
267         // 3rd element
268         Assertions.assertEquals("name6", elements.get(2).getName());
269         Assertions.assertEquals("", elements.get(2).getValue());
270         // 3rd element has 2 getParameters()
271         Assertions.assertEquals(2, elements.get(2).getParameters().length);
272         Assertions.assertEquals("name7", elements.get(2).getParameters()[0].getName());
273         Assertions.assertEquals("value7", elements.get(2).getParameters()[0].getValue());
274         Assertions.assertEquals("name8", elements.get(2).getParameters()[1].getName());
275         Assertions.assertEquals(" value8", elements.get(2).getParameters()[1].getValue());
276     }
277 
278     @Test
279     public void testParamListFormatting() throws Exception {
280         final CharArrayBuffer buf = new CharArrayBuffer(64);
281         MessageSupport.formatParameters(buf, Arrays.asList(
282                 new BasicNameValuePair("param", "regular_stuff"),
283                 new BasicNameValuePair("param", "this\\that"),
284                 new BasicNameValuePair("param", "this,that")
285         ));
286         Assertions.assertEquals("param=regular_stuff; param=\"this\\\\that\"; param=\"this,that\"",
287                 buf.toString());
288     }
289 
290     @Test
291     public void testParamArrayFormatting() throws Exception {
292         final CharArrayBuffer buf = new CharArrayBuffer(64);
293         MessageSupport.formatParameters(buf,
294                 new BasicNameValuePair("param", "regular_stuff"),
295                 new BasicNameValuePair("param", "this\\that"),
296                 new BasicNameValuePair("param", "this,that")
297         );
298         Assertions.assertEquals("param=regular_stuff; param=\"this\\\\that\"; param=\"this,that\"",
299                 buf.toString());
300     }
301 
302     @Test
303     public void testParseParams() {
304         final String s =
305                 "test; test1 =  stuff   ; test2 =  \"stuff; stuff\"; test3=stuff,123";
306         final CharArrayBuffer buffer = new CharArrayBuffer(16);
307         buffer.append(s);
308         final ParserCursor cursor = new ParserCursor(0, s.length());
309 
310         final List<NameValuePair> params = new ArrayList<>();
311         MessageSupport.parseParameters(buffer, cursor, params::add);
312         Assertions.assertEquals("test", params.get(0).getName());
313         Assertions.assertNull(params.get(0).getValue());
314         Assertions.assertEquals("test1", params.get(1).getName());
315         Assertions.assertEquals("stuff", params.get(1).getValue());
316         Assertions.assertEquals("test2", params.get(2).getName());
317         Assertions.assertEquals("stuff; stuff", params.get(2).getValue());
318         Assertions.assertEquals("test3", params.get(3).getName());
319         Assertions.assertEquals("stuff", params.get(3).getValue());
320         Assertions.assertEquals(s.length() - 4, cursor.getPos());
321         Assertions.assertFalse(cursor.atEnd());
322     }
323 
324     @Test
325     public void testAddContentHeaders() throws Exception {
326         final HttpEntity entity = HttpEntities.create("some stuff with trailers", StandardCharsets.US_ASCII,
327                 new BasicHeader("z", "this"), new BasicHeader("b", "that"), new BasicHeader("a", "this and that"));
328         final HttpMessage message = new BasicHttpResponse(200);
329         MessageSupport.addTrailerHeader(message, entity);
330         MessageSupport.addContentTypeHeader(message, entity);
331 
332         final Header h1 = message.getFirstHeader(HttpHeaders.TRAILER);
333         final Header h2 = message.getFirstHeader(HttpHeaders.CONTENT_TYPE);
334 
335         Assertions.assertNotNull(h1);
336         Assertions.assertEquals("z, b, a", h1.getValue());
337         Assertions.assertNotNull(h2);
338         Assertions.assertEquals("text/plain; charset=US-ASCII", h2.getValue());
339     }
340 
341     @Test
342     public void testContentHeadersAlreadyPresent() throws Exception {
343         final HttpEntity entity = HttpEntities.create("some stuff with trailers", StandardCharsets.US_ASCII,
344                 new BasicHeader("z", "this"), new BasicHeader("b", "that"), new BasicHeader("a", "this and that"));
345         final HttpMessage message = new BasicHttpResponse(200);
346         message.addHeader(HttpHeaders.TRAILER, "a, a, a");
347         message.addHeader(HttpHeaders.CONTENT_TYPE, "text/plain; charset=ascii");
348 
349         MessageSupport.addTrailerHeader(message, entity);
350         MessageSupport.addContentTypeHeader(message, entity);
351 
352         final Header h1 = message.getFirstHeader(HttpHeaders.TRAILER);
353         final Header h2 = message.getFirstHeader(HttpHeaders.CONTENT_TYPE);
354 
355         Assertions.assertNotNull(h1);
356         Assertions.assertEquals("a, a, a", h1.getValue());
357         Assertions.assertNotNull(h2);
358         Assertions.assertEquals("text/plain; charset=ascii", h2.getValue());
359     }
360 
361     @Test
362     public void testHopByHopHeaders() {
363         Assertions.assertTrue(MessageSupport.isHopByHop("Connection"));
364         Assertions.assertTrue(MessageSupport.isHopByHop("connection"));
365         Assertions.assertTrue(MessageSupport.isHopByHop("coNNection"));
366         Assertions.assertFalse(MessageSupport.isHopByHop("Content-Type"));
367         Assertions.assertFalse(MessageSupport.isHopByHop("huh"));
368     }
369 
370     @Test
371     public void testHopByHopHeadersConnectionSpecific() {
372         final HttpResponse response = BasicResponseBuilder.create(HttpStatus.SC_OK)
373                 .addHeader(HttpHeaders.CONNECTION, "blah, blah, this, that")
374                 .addHeader(HttpHeaders.CONTENT_TYPE, ContentType.TEXT_PLAIN.toString())
375                 .build();
376         final Set<String> hopByHopConnectionSpecific = MessageSupport.hopByHopConnectionSpecific(response);
377         Assertions.assertTrue(hopByHopConnectionSpecific.contains("Connection"));
378         Assertions.assertTrue(hopByHopConnectionSpecific.contains("connection"));
379         Assertions.assertTrue(hopByHopConnectionSpecific.contains("coNNection"));
380         Assertions.assertFalse(hopByHopConnectionSpecific.contains("Content-Type"));
381         Assertions.assertTrue(hopByHopConnectionSpecific.contains("blah"));
382         Assertions.assertTrue(hopByHopConnectionSpecific.contains("Blah"));
383         Assertions.assertTrue(hopByHopConnectionSpecific.contains("This"));
384         Assertions.assertTrue(hopByHopConnectionSpecific.contains("That"));
385     }
386 
387 }