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