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.util.Arrays;
31  import java.util.BitSet;
32  import java.util.Iterator;
33  import java.util.LinkedHashSet;
34  import java.util.Set;
35  
36  import org.apache.hc.core5.http.EntityDetails;
37  import org.apache.hc.core5.http.FormattedHeader;
38  import org.apache.hc.core5.http.Header;
39  import org.apache.hc.core5.http.HeaderElement;
40  import org.apache.hc.core5.http.HttpHeaders;
41  import org.apache.hc.core5.http.HttpMessage;
42  import org.apache.hc.core5.http.HttpResponse;
43  import org.apache.hc.core5.http.HttpStatus;
44  import org.apache.hc.core5.http.MessageHeaders;
45  import org.apache.hc.core5.util.Args;
46  import org.apache.hc.core5.util.CharArrayBuffer;
47  import org.apache.hc.core5.util.TextUtils;
48  
49  /**
50   * Message support functions.
51   *
52   * @since 5.0
53   */
54  public class MessageSupport {
55  
56      private MessageSupport() {
57          // Do not allow utility class to be instantiated.
58      }
59  
60      public static void formatTokens(final CharArrayBuffer dst, final String... tokens) {
61          Args.notNull(dst, "Destination");
62          Arrays.sort(tokens);
63          for (int i = 0; i < tokens.length; i++) {
64              final String element = tokens[i];
65              if (i > 0) {
66                  dst.append(", ");
67              }
68              dst.append(element);
69          }
70      }
71  
72      public static void formatTokens(final CharArrayBuffer dst, final Set<String> tokens) {
73          Args.notNull(dst, "Destination");
74          if (tokens == null || tokens.isEmpty()) {
75              return;
76          }
77          formatTokens(dst, tokens.toArray(new String[tokens.size()]));
78      }
79  
80      public static Header format(final String name, final Set<String> tokens) {
81          Args.notBlank(name, "Header name");
82          if (tokens == null || tokens.isEmpty()) {
83              return null;
84          }
85          final CharArrayBuffer buffer = new CharArrayBuffer(256);
86          buffer.append(name);
87          buffer.append(": ");
88          formatTokens(buffer, tokens);
89          return BufferedHeader.create(buffer);
90      }
91  
92      public static Header format(final String name, final String... tokens) {
93          Args.notBlank(name, "Header name");
94          if (tokens == null || tokens.length == 0) {
95              return null;
96          }
97          final CharArrayBuffer buffer = new CharArrayBuffer(256);
98          buffer.append(name);
99          buffer.append(": ");
100         formatTokens(buffer, tokens);
101         return BufferedHeader.create(buffer);
102     }
103 
104     private static final BitSet COMMA = TokenParser.INIT_BITSET(',');
105 
106     public static Set<String> parseTokens(final CharSequence src, final ParserCursor cursor) {
107         Args.notNull(src, "Source");
108         Args.notNull(cursor, "Cursor");
109         final Set<String> tokens = new LinkedHashSet<>();
110         while (!cursor.atEnd()) {
111             final int pos = cursor.getPos();
112             if (src.charAt(pos) == ',') {
113                 cursor.updatePos(pos + 1);
114             }
115             final String token = TokenParser.INSTANCE.parseToken(src, cursor, COMMA);
116             if (!TextUtils.isBlank(token)) {
117                 tokens.add(token);
118             }
119         }
120         return tokens;
121     }
122 
123     public static Set<String> parseTokens(final Header header) {
124         Args.notNull(header, "Header");
125         if (header instanceof FormattedHeader) {
126             final CharArrayBuffer buf = ((FormattedHeader) header).getBuffer();
127             final ParserCursor cursor = new ParserCursor(0, buf.length());
128             cursor.updatePos(((FormattedHeader) header).getValuePos());
129             return parseTokens(buf, cursor);
130         } else {
131             final String value = header.getValue();
132             final ParserCursor cursor = new ParserCursor(0, value.length());
133             return parseTokens(value, cursor);
134         }
135     }
136 
137     public static void addContentTypeHeader(final HttpMessage message, final EntityDetails entity) {
138         if (entity != null && entity.getContentType() != null && !message.containsHeader(HttpHeaders.CONTENT_TYPE)) {
139             message.addHeader(new BasicHeader(HttpHeaders.CONTENT_TYPE, entity.getContentType()));
140         }
141     }
142 
143     public static void addContentEncodingHeader(final HttpMessage message, final EntityDetails entity) {
144         if (entity != null && entity.getContentEncoding() != null && !message.containsHeader(HttpHeaders.CONTENT_ENCODING)) {
145             message.addHeader(new BasicHeader(HttpHeaders.CONTENT_ENCODING, entity.getContentEncoding()));
146         }
147     }
148 
149     public static void addTrailerHeader(final HttpMessage message, final EntityDetails entity) {
150         if (entity != null && !message.containsHeader(HttpHeaders.TRAILER)) {
151             final Set<String> trailerNames = entity.getTrailerNames();
152             if (trailerNames != null && !trailerNames.isEmpty()) {
153                 message.setHeader(MessageSupport.format(HttpHeaders.TRAILER, trailerNames));
154             }
155         }
156     }
157 
158     public static Iterator<HeaderElement> iterate(final MessageHeaders headers, final String name) {
159         Args.notNull(headers, "Message headers");
160         Args.notBlank(name, "Header name");
161         return new BasicHeaderElementIterator(headers.headerIterator(name));
162     }
163 
164     public static HeaderElement[] parse(final Header header) {
165         Args.notNull(header, "Headers");
166         final String value = header.getValue();
167         if (value == null) {
168             return new HeaderElement[] {};
169         }
170         final ParserCursor cursor = new ParserCursor(0, value.length());
171         return BasicHeaderValueParser.INSTANCE.parseElements(value, cursor);
172     }
173 
174     /**
175      * @since  5.0
176      */
177     public static boolean canResponseHaveBody(final String method, final HttpResponse response) {
178         if ("HEAD".equalsIgnoreCase(method)) {
179             return false;
180         }
181         final int status = response.getCode();
182         if ("CONNECT".equalsIgnoreCase(method) && status == HttpStatus.SC_OK) {
183             return false;
184         }
185         return status >= HttpStatus.SC_SUCCESS
186                 && status != HttpStatus.SC_NO_CONTENT
187                 && status != HttpStatus.SC_NOT_MODIFIED;
188     }
189 
190 }