View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package org.jboss.netty.handler.codec.http;
17  
18  import java.io.UnsupportedEncodingException;
19  import java.net.URI;
20  import java.net.URISyntaxException;
21  import java.net.URLEncoder;
22  import java.nio.charset.Charset;
23  import java.nio.charset.UnsupportedCharsetException;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  /**
28   * Creates an URL-encoded URI from a path string and key-value parameter pairs.
29   * This encoder is for one time use only.  Create a new instance for each URI.
30   *
31   * <pre>
32   * {@link QueryStringEncoder} encoder = new {@link QueryStringEncoder}("/hello");
33   * encoder.addParam("recipient", "world");
34   * assert encoder.toString().equals("/hello?recipient=world");
35   * </pre>
36   * @see QueryStringDecoder
37   *
38   * @apiviz.stereotype utility
39   * @apiviz.has        org.jboss.netty.handler.codec.http.HttpRequest oneway - - encodes
40   */
41  public class QueryStringEncoder {
42  
43      private final Charset charset;
44      private final String uri;
45      private final List<Param> params = new ArrayList<Param>();
46  
47      /**
48       * Creates a new encoder that encodes a URI that starts with the specified
49       * path string.  The encoder will encode the URI in UTF-8.
50       */
51      public QueryStringEncoder(String uri) {
52          this(uri, HttpConstants.DEFAULT_CHARSET);
53      }
54  
55      /**
56       * Creates a new encoder that encodes a URI that starts with the specified
57       * path string in the specified charset.
58       */
59      public QueryStringEncoder(String uri, Charset charset) {
60          if (uri == null) {
61              throw new NullPointerException("uri");
62          }
63          if (charset == null) {
64              throw new NullPointerException("charset");
65          }
66  
67          this.uri = uri;
68          this.charset = charset;
69      }
70  
71      /**
72       * Adds a parameter with the specified name and value to this encoder.
73       */
74      public void addParam(String name, String value) {
75          if (name == null) {
76              throw new NullPointerException("name");
77          }
78          if (value == null) {
79              throw new NullPointerException("value");
80          }
81          params.add(new Param(name, value));
82      }
83  
84      /**
85       * Returns the URL-encoded URI object which was created from the path string
86       * specified in the constructor and the parameters added by
87       * {@link #addParam(String, String)} method.
88       */
89      public URI toUri() throws URISyntaxException {
90          return new URI(toString());
91      }
92  
93      /**
94       * Returns the URL-encoded URI which was created from the path string
95       * specified in the constructor and the parameters added by
96       * {@link #addParam(String, String)} method.
97       */
98      @Override
99      public String toString() {
100         if (params.isEmpty()) {
101             return uri;
102         } else {
103             StringBuilder sb = new StringBuilder(uri).append('?');
104             for (int i = 0; i < params.size(); i++) {
105                 Param param = params.get(i);
106                 sb.append(encodeComponent(param.name, charset));
107                 sb.append('=');
108                 sb.append(encodeComponent(param.value, charset));
109                 if (i != params.size() - 1) {
110                     sb.append('&');
111                 }
112             }
113             return sb.toString();
114         }
115     }
116 
117     private static String encodeComponent(String s, Charset charset) {
118         try {
119             return URLEncoder.encode(s, charset.name()).replaceAll("\\+", "%20");
120         } catch (UnsupportedEncodingException e) {
121             throw new UnsupportedCharsetException(charset.name());
122         }
123     }
124 
125     private static final class Param {
126 
127         final String name;
128         final String value;
129 
130         Param(String name, String value) {
131             this.value = value;
132             this.name = name;
133         }
134     }
135 }