View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.rest.client;
18  
19  import static java.time.format.DateTimeFormatter.*;
20  import static java.time.temporal.ChronoUnit.*;
21  import static org.apache.juneau.TestUtils.*;
22  import static org.apache.juneau.commons.utils.CollectionUtils.*;
23  import static org.apache.juneau.http.HttpHeaders.*;
24  import static org.apache.juneau.httppart.HttpPartSchema.*;
25  
26  import java.time.*;
27  
28  import org.apache.juneau.*;
29  import org.apache.juneau.http.header.*;
30  import org.apache.juneau.httppart.*;
31  import org.apache.juneau.marshaller.*;
32  import org.apache.juneau.rest.annotation.*;
33  import org.apache.juneau.rest.httppart.*;
34  import org.apache.juneau.rest.logger.*;
35  import org.apache.juneau.rest.mock.*;
36  import org.apache.juneau.rest.servlet.*;
37  import org.apache.juneau.serializer.*;
38  import org.apache.juneau.uon.*;
39  import org.apache.juneau.utest.utils.*;
40  import org.junit.jupiter.api.*;
41  
42  public class RestClient_Headers_Test extends TestBase {
43  
44  	public static final CaptureLogger LOGGER = new CaptureLogger();
45  
46  	public static class CaptureLogger extends BasicTestCaptureCallLogger {
47  		public static CaptureLogger getInstance() {
48  			return LOGGER;
49  		}
50  	}
51  
52  	public static class ABean {
53  		public int f;
54  		static ABean get() {
55  			var x = new ABean();
56  			x.f = 1;
57  			return x;
58  		}
59  		@Override
60  		public String toString() {
61  			return Json5.of(this);
62  		}
63  	}
64  
65  	private static ABean bean = ABean.get();
66  
67  	@Rest(callLogger=CaptureLogger.class)
68  	public static class A extends BasicRestObject {
69  		@RestGet
70  		public String[] headers(org.apache.juneau.rest.RestRequest req) {
71  			return req.getHeaders().getAll(req.getHeaderParam("Check").orElse(null)).stream().map(RequestHeader::getValue).toArray(String[]::new);
72  		}
73  	}
74  
75  	private static final ZonedDateTime ZONEDDATETIME = ZonedDateTime.from(RFC_1123_DATE_TIME.parse("Mon, 3 Dec 2007 10:15:30 GMT")).truncatedTo(SECONDS);
76  	private static final String PARSEDZONEDDATETIME = "Mon, 3 Dec 2007 10:15:30 GMT";
77  
78  	//------------------------------------------------------------------------------------------------------------------
79  	// Method tests
80  	//------------------------------------------------------------------------------------------------------------------
81  
82  	@Test void a01_header_String_Object() throws Exception {
83  		checkFooClient().header("Foo","bar").build().get("/headers").run().assertContent("['bar']");
84  		checkFooClient().build().get("/headers").header("Foo","baz").run().assertContent("['baz']");
85  		checkFooClient().header("Foo","bar").build().get("/headers").header("Foo","baz").run().assertContent("['bar','baz']");
86  		checkFooClient().headers(header("Foo",bean,null)).build().get("/headers").header("Foo",bean).run().assertContent("['f=1','f=1']");
87  		checkFooClient().headers(header("Foo",null,null)).build().get("/headers").header("Foo",null).run().assertContent("[]");
88  	}
89  
90  	@Test void a02_header_String_Object_Schema() throws Exception {
91  		var l1 = l("bar","baz");
92  		var l2 = l("qux","quux");
93  		checkFooClient().headers(header("Foo",l1,T_ARRAY_PIPES)).build().get("/headers").header(header("Foo",l2,T_ARRAY_PIPES)).run().assertContent("['bar|baz','qux|quux']");
94  	}
95  
96  	@Test void a03_header_Header() throws Exception {
97  		checkFooClient().headers(header("Foo","bar")).build().get("/headers").header(header("Foo","baz")).run().assertContent("['bar','baz']");
98  		checkFooClient().headers(stringHeader("Foo","bar")).build().get("/headers").header(stringHeader("Foo","baz")).run().assertContent("['bar','baz']");
99  	}
100 
101 	@Test void a08_header_String_Supplier() throws Exception {
102 		var s = MutableSupplier.of("foo");
103 		var x = checkFooClient().headers(header("Foo",s,null)).build();
104 		x.get("/headers").header("Foo",s).run().assertContent("['foo','foo']");
105 		s.set("bar");
106 		x.get("/headers").header("Foo",s).run().assertContent("['bar','bar']");
107 	}
108 
109 	@Test void a09_headers_String_Object_Schema_Serializer() throws Exception {
110 		checkFooClient().headers(header("Foo",bean,null).serializer(FakeWriterSerializer.X)).build().get("/headers").run().assertContent("['x{f:1}x']");
111 	}
112 
113 	@Test void a10_headers_String_Supplier_Schema() throws Exception {
114 		var s = MutableSupplier.of(a("foo","bar"));
115 		var x = checkFooClient().headers(header("Foo",s,T_ARRAY_PIPES)).build();
116 		x.get("/headers").header(header("Foo",s,T_ARRAY_PIPES)).run().assertContent("['foo|bar','foo|bar']");
117 		s.set(a("bar","baz"));
118 		x.get("/headers").header(header("Foo",s,T_ARRAY_PIPES)).run().assertContent("['bar|baz','bar|baz']");
119 	}
120 
121 	@Test void a11_headers_String_Supplier_Schema_Serializer() throws Exception {
122 		var s = MutableSupplier.of(a("foo","bar"));
123 		checkFooClient().headers(header("Foo",s,T_ARRAY_PIPES).serializer(UonSerializer.DEFAULT)).build().get("/headers").run().assertContent("['@(foo,bar)']");
124 	}
125 
126 	public static class A12 implements HttpPartSerializer {
127 		@Override
128 		public HttpPartSerializerSession getPartSession() {
129 			return (type, schema, value) -> {
130 				throw new SerializeException("bad");
131 			};
132 		}
133 	}
134 
135 	@Test void a12_badSerialization() {
136 		assertThrowsWithMessage(Exception.class, "bad", ()->checkFooClient().headers(header("Foo","bar",null).serializer(new A12())).build().get().run());
137 	}
138 
139 	//------------------------------------------------------------------------------------------------------------------
140 	// Other tests
141 	//------------------------------------------------------------------------------------------------------------------
142 
143 	@Test void b01_standardHeaders() throws Exception {
144 		checkClient("Accept").accept("text/plain").build().get("/headers").run().assertContent("['text/plain']");
145 		checkClient("Accept-Charset").acceptCharset("UTF-8").build().get("/headers").run().assertContent("['UTF-8']");
146 		checkClient("Client-Version").clientVersion("1").build().get("/headers").run().assertContent("['1']");
147 		checkClient("Content-Type").contentType("foo").build().get("/headers").run().assertContent("['foo']");
148 		checkClient("No-Trace").noTrace().build().get("/headers").run().assertContent("['true','true']");
149 
150 		checkClient("Accept").build().get("/headers").accept("text/plain").run().assertContent("['text/plain']");
151 		checkClient("Accept-Charset").build().get("/headers").acceptCharset("UTF-8").run().assertContent("['UTF-8']");
152 		checkClient("Content-Type").build().get("/headers").contentType("foo").run().assertContent("['foo']");
153 		checkClient("No-Trace").build().get("/headers").noTrace().run().assertContent("['true','true']");
154 	}
155 
156 	@Test void b02_headerBeans() throws Exception {
157 		checkClient("Accept").headers(new Accept("text/plain")).build().get("/headers").run().assertContent("['text/plain']");
158 		checkClient("Accept-Charset").headers(new AcceptCharset("UTF-8")).build().get("/headers").run().assertContent("['UTF-8']");
159 		checkClient("Accept-Encoding").headers(new AcceptEncoding("identity")).build().get("/headers").run().assertContent("['identity']");
160 		checkClient("Accept-Language").headers(new AcceptLanguage("en")).build().get("/headers").run().assertContent("['en']");
161 		checkClient("Authorization").headers(new Authorization("foo")).build().get("/headers").run().assertContent("['foo']");
162 		checkClient("Cache-Control").headers(new CacheControl("none")).header("X-Expect","none").build().get("/headers").run().assertContent("['none']");
163 		checkClient("Client-Version").headers(new ClientVersion("1")).build().get("/headers").run().assertContent("['1']");
164 		checkClient("Connection").headers(new Connection("foo")).build().get("/headers").run().assertContent("['foo']");
165 		checkClient("Content-Length").headers(new ContentLength(123L)).build().get("/headers").run().assertContent("['123']");
166 		checkClient("Content-Type").headers(new ContentType("foo")).build().get("/headers").run().assertContent("['foo']");
167 		checkClient("Date").headers(new org.apache.juneau.http.header.Date(PARSEDZONEDDATETIME)).build().get("/headers").run().assertContent("['"+PARSEDZONEDDATETIME+"']");
168 		checkClient("Date").headers(new org.apache.juneau.http.header.Date(ZONEDDATETIME)).build().get("/headers").run().assertContent("['"+PARSEDZONEDDATETIME+"']");
169 		checkClient("Expect").headers(new Expect("foo")).build().get("/headers").run().assertContent("['foo']");
170 		checkClient("Forwarded").headers(new Forwarded("foo")).build().get("/headers").run().assertContent("['foo']");
171 		checkClient("From").headers(new From("foo")).build().get("/headers").run().assertContent("['foo']");
172 		checkClient("Host").headers(new Host("foo")).build().get("/headers").run().assertContent("['foo']");
173 		checkClient("If-Match").headers(new IfMatch("\"foo\"")).build().get("/headers").run().assertContent("['\"foo\"']");
174 		checkClient("If-Modified-Since").headers(new IfModifiedSince(ZONEDDATETIME)).build().get("/headers").run().assertContent("['"+PARSEDZONEDDATETIME+"']");
175 		checkClient("If-Modified-Since").headers(new IfModifiedSince(PARSEDZONEDDATETIME)).build().get("/headers").run().assertContent("['"+PARSEDZONEDDATETIME+"']");
176 		checkClient("If-None-Match").headers(new IfNoneMatch("\"foo\"")).build().get("/headers").run().assertContent("['\"foo\"']");
177 		checkClient("If-Range").headers(new IfRange("\"foo\"")).build().get("/headers").run().assertContent("['\"foo\"']");
178 		checkClient("If-Unmodified-Since").headers(new IfUnmodifiedSince(ZONEDDATETIME)).build().get("/headers").run().assertContent("['"+PARSEDZONEDDATETIME+"']");
179 		checkClient("If-Unmodified-Since").headers(new IfUnmodifiedSince(PARSEDZONEDDATETIME)).build().get("/headers").run().assertContent("['"+PARSEDZONEDDATETIME+"']");
180 		checkClient("Max-Forwards").headers(new MaxForwards(10)).build().get("/headers").run().assertContent("['10']");
181 		checkClient("No-Trace").headers(new NoTrace("true")).build().get("/headers").run().assertContent("['true','true']");
182 		checkClient("Origin").headers(new Origin("foo")).build().get("/headers").run().assertContent("['foo']");
183 		checkClient("Pragma").headers(new Pragma("foo")).build().get("/headers").run().assertContent("['foo']");
184 		checkClient("Proxy-Authorization").headers(new ProxyAuthorization("foo")).build().get("/headers").run().assertContent("['foo']");
185 		checkClient("Range").headers(new Range("foo")).build().get("/headers").run().assertContent("['foo']");
186 		checkClient("Referer").headers(new Referer("foo")).build().get("/headers").run().assertContent("['foo']");
187 		checkClient("TE").headers(new TE("foo")).build().get("/headers").run().assertContent("['foo']");
188 		checkClient("User-Agent").headers(new UserAgent("foo")).build().get("/headers").run().assertContent("['foo']");
189 		checkClient("Upgrade").headers(new Upgrade("foo")).build().get("/headers").run().assertContent("['foo']");
190 		checkClient("Via").headers(new Via("foo")).build().get("/headers").run().assertContent("['foo']");
191 		checkClient("Warning").headers(new Warning("foo")).build().get("/headers").run().assertContent("['foo']");
192 	}
193 
194 	@Test void b03_debugHeader() throws Exception {
195 		checkClient("Debug").build().get("/headers").debug().suppressLogging().run().assertContent("['true']");
196 	}
197 
198 	@Test void b04_dontOverrideAccept() throws Exception {
199 		checkClient("Accept").header("Accept","text/plain").build().get("/headers").run().assertContent("['text/plain']");
200 		checkClient("Accept").header("Accept","text/foo").build().get("/headers").header("Accept","text/plain").run().assertContent("['text/foo','text/plain']");
201 		var rc = checkClient("Accept").header("Accept","text/foo").build();
202 		var req = rc.get("/headers");
203 		req.setHeader("Accept","text/plain");
204 		req.run().assertContent("['text/plain']");
205 	}
206 
207 	@Test void b05_dontOverrideContentType() throws Exception {
208 		checkClient("Content-Type").header("Content-Type","text/plain").build().get("/headers").run().assertContent("['text/plain']");
209 		checkClient("Content-Type").header("Content-Type","text/foo").build().get("/headers").header("Content-Type","text/plain").run().assertContent("['text/foo','text/plain']");
210 	}
211 
212 	//------------------------------------------------------------------------------------------------------------------
213 	// Helper methods.
214 	//------------------------------------------------------------------------------------------------------------------
215 
216 	private static org.apache.http.Header header(String name, String val) {
217 		return basicHeader(name, val);
218 	}
219 
220 	private static SerializedHeader header(String name, Object val, HttpPartSchema schema) {
221 		return serializedHeader(name, val).schema(schema);
222 	}
223 
224 	private static RestClient.Builder checkFooClient() {
225 		return MockRestClient.create(A.class).json5().header("Check","Foo");
226 	}
227 
228 	private static RestClient.Builder checkClient(String headerToCheck) {
229 		return MockRestClient.create(A.class).json5().header("Check",headerToCheck).noTrace();
230 	}
231 }