1 /*
2 * Copyright 2009 Red Hat, Inc.
3 *
4 * Red Hat licenses this file to you under the Apache License, version 2.0
5 * (the "License"); you may not use this file except in compliance with the
6 * 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.http2;
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 QueryStringDecoder}("/hello");
33 * encoder.addParam("recipient", "world");
34 * assert encoder.toString().equals("/hello?recipient=world");
35 * </pre>
36 *
37 * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
38 * @author Andy Taylor (andy.taylor@jboss.org)
39 * @author <a href="http://gleamynode.net/">Trustin Lee</a>
40 * @version $Rev: 1107 $, $Date: 2012-04-15 19:00:57 +0200 (dim., 15 avr. 2012) $
41 *
42 * @see QueryStringDecoder
43 *
44 * @apiviz.stereotype utility
45 * @apiviz.has org.jboss.netty.handler.codec.http2.HttpRequest oneway - - encodes
46 */
47 public class QueryStringEncoder {
48
49 private final Charset charset;
50 private final String uri;
51 private final List<Param> params = new ArrayList<Param>();
52
53 /**
54 * Creates a new encoder that encodes a URI that starts with the specified
55 * path string. The encoder will encode the URI in UTF-8.
56 */
57 public QueryStringEncoder(String uri) {
58 this(uri, HttpCodecUtil.DEFAULT_CHARSET);
59 }
60
61 /**
62 * Creates a new encoder that encodes a URI that starts with the specified
63 * path string in the specified charset.
64 */
65 public QueryStringEncoder(String uri, Charset charset) {
66 if (uri == null) {
67 throw new NullPointerException("uri");
68 }
69 if (charset == null) {
70 throw new NullPointerException("charset");
71 }
72
73 this.uri = uri;
74 this.charset = charset;
75 }
76
77 /**
78 * @deprecated Use {@link #QueryStringEncoder(String, Charset)} instead.
79 */
80 @Deprecated
81 public QueryStringEncoder(String uri, String charset) {
82 this(uri, Charset.forName(charset));
83 }
84
85 /**
86 * Adds a parameter with the specified name and value to this encoder.
87 */
88 public void addParam(String name, String value) {
89 if (name == null) {
90 throw new NullPointerException("name");
91 }
92 if (value == null) {
93 throw new NullPointerException("value");
94 }
95 params.add(new Param(name, value));
96 }
97
98 /**
99 * Returns the URL-encoded URI object which was created from the path string
100 * specified in the constructor and the parameters added by
101 * {@link #addParam(String, String)} method.
102 */
103 public URI toUri() throws URISyntaxException {
104 return new URI(toString());
105 }
106
107 /**
108 * Returns the URL-encoded URI which was created from the path string
109 * specified in the constructor and the parameters added by
110 * {@link #addParam(String, String)} method.
111 */
112 @Override
113 public String toString() {
114 if (params.isEmpty()) {
115 return uri;
116 } else {
117 StringBuilder sb = new StringBuilder(uri).append("?");
118 for (int i = 0; i < params.size(); i++) {
119 Param param = params.get(i);
120 sb.append(encodeComponent(param.name, charset));
121 sb.append("=");
122 sb.append(encodeComponent(param.value, charset));
123 if (i != params.size() - 1) {
124 sb.append("&");
125 }
126 }
127 return sb.toString();
128 }
129 }
130
131 private static String encodeComponent(String s, Charset charset) {
132 try {
133 return URLEncoder.encode(s, charset.name()).replaceAll("\\+", "%20");
134 } catch (UnsupportedEncodingException e) {
135 throw new UnsupportedCharsetException(charset.name());
136 }
137 }
138
139 private static final class Param {
140
141 final String name;
142 final String value;
143
144 Param(String name, String value) {
145 this.value = value;
146 this.name = name;
147 }
148 }
149 }