001package com.thetransactioncompany.jsonrpc2.client;
002
003
004import java.net.Proxy;
005
006import java.util.regex.Pattern;
007
008
009/**
010 * Optional settings for JSON-RPC 2.0 client sessions. The no-argument 
011 * constructor specifies the default settings that the {@link JSONRPC2Session}
012 * uses. To apply different ones instantiate a new settings instance, set the
013 * desired ones to your liking, and then {@link JSONRPC2Session#setOptions pass} 
014 * it to your {@link JSONRPC2Session} instance.
015 * 
016 * <p>Overview of the available session options:
017 *
018 * <ul>
019 *     <li>Customise the "Content-Type" header in HTTP POST requests.
020 *     <li>Set an "Origin" header in HTTP POST requests to simulate 
021 *         Cross-Origin Resource Sharing (CORS) requests from a browser.
022 *     <li>Accept HTTP cookies (if client sessions are established by this 
023 *         mean instead of through the JSON-RPC protocol itself).
024 *     <li>Customise the allowable "Content-Type" header values in HTTP POST
025 *         responses.
026 *     <li>Preserve parse order of JSON object members in JSON-RPC 2.0 response
027 *         results (for human-facing clients, e.g. the JSON-RPC 2.0 Shell).
028 *     <li>Ignore version 2.0 checks when parsing responses to allow client 
029 *         sessions to older JSON-RPC (1.0) servers.
030 *     <li>Parse non-standard attributes in JSON-RPC 2.0 responses.
031 *     <li>Set an HTTP connect timeout.
032 *     <li>Set an HTTP read timeout.
033 *     <li>Set an HTTP proxy.
034 *     <li>Enable HTTP response compression (using GZIP or DEFLATE content
035 *         encoding).
036 *     <li>Trust all X.509 server certificates (for HTTPS connections), 
037 *         including self-signed.
038 * </ul>
039 *
040 * @since 1.4
041 * @author Vladimir Dzhuvinov
042 */
043public class JSONRPC2SessionOptions {
044        
045        
046        /**
047         * The "Content-Type" (MIME) header value of HTTP POST requests. If
048         * {@code null} the header will not be set.
049         */
050        private String requestContentType = DEFAULT_CONTENT_TYPE;
051        
052        
053        /**
054         * The default "Content-Type" (MIME) header value of HTTP POST 
055         * requests. Set to {@code application/json}.
056         */
057        public static final String DEFAULT_CONTENT_TYPE = "application/json";
058        
059        
060        /**
061         * The allowed "Content-Type" (MIME) header values of HTTP responses. 
062         * If {@code null} any header value will be accepted.
063         */
064        private String[] allowedResponseContentTypes = 
065                DEFAULT_ALLOWED_RESPONSE_CONTENT_TYPES;
066        
067        
068        /**
069         * The default allowed "Content-Type" (MIME) header values of HTTP
070         * responses. Set to {@code application/json} and {@code text/plain}.
071         */
072        public static final String[] DEFAULT_ALLOWED_RESPONSE_CONTENT_TYPES =
073                {"application/json", "text/plain"};
074         
075         
076        /** 
077         * Optional CORS "Origin" header. If {@code null} the header will not 
078         * be set.
079         */
080        private String origin = DEFAULT_ORIGIN;
081        
082        
083        /**
084         * The default CORS "Origin" header value. Set to {@code null} (none).
085         */
086        public static final String DEFAULT_ORIGIN = null;
087        
088        
089        /**
090         * Specifies whether to accept HTTP cookies.
091         */
092        private boolean acceptCookies = DEFAULT_ACCEPT_COOKIES;
093        
094        
095        /**
096         * The default HTTP cookie acceptance policy.
097         */
098        public static final boolean DEFAULT_ACCEPT_COOKIES = false;
099        
100        
101        /**
102         * If {@code true} the order of parsed JSON object members must be
103         * preserved.
104         */
105        private boolean preserveObjectMemberOrder = 
106                DEFAULT_PRESERVE_OBJECT_MEMBER_ORDER;
107        
108        
109        /**
110         * The default policy for preserving the order of parsed JSON object
111         * members. Set to {@code false} (no preserve).
112         */
113        public static final boolean DEFAULT_PRESERVE_OBJECT_MEMBER_ORDER = false;
114        
115        
116        /**
117         * If {@code true} version 2.0 checking of received responses must be
118         * disabled.
119         */
120        private boolean ignoreVersion = DEFAULT_IGNORE_VERSION ;
121        
122        
123        /**
124         * The default policy for version 2.0 checking. Set to {@code false}
125         * (strict checking).
126         */
127        public static final boolean DEFAULT_IGNORE_VERSION = false;
128        
129        
130        /**
131         * If {@code true} non-standard attributes appended to the JSON-RPC 2.0
132         * responses must be parsed too.
133         */
134        private boolean parseNonStdAttributes = DEFAULT_PARSE_NON_STD_ATTRIBUTES;
135        
136        
137        /**
138         * The default policy for parsing non-standard attributes in JSON-RPC 
139         * 2.0 messages. Set to {@code false} (non-standard attributes ignored).
140         */
141        public static final boolean DEFAULT_PARSE_NON_STD_ATTRIBUTES = false;
142        
143        
144        /**
145         * The HTTP connect timeout, in milliseconds. Zero implies the option 
146         * is disabled (timeout of infinity).
147         */
148        private int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
149        
150        
151        /**
152         * The default HTTP connect timeout. Set to zero (disabled).
153         */
154        public static final int DEFAULT_CONNECT_TIMEOUT = 0;
155        
156        
157        /**
158         * The HTTP read timeout, in milliseconds. Zero implies the option is
159         * disabled (timeout of infinity).
160         */
161        private int readTimeout = DEFAULT_READ_TIMEOUT;
162        
163        
164        /**
165         * The default HTTP read timeout. Set to zero (disabled).
166         */
167        public static final int DEFAULT_READ_TIMEOUT = 0;
168
169
170        /**
171         * Optional HTTP proxy.
172         */
173        private Proxy proxy = null;
174
175
176        /**
177         * Enable / disable HTTP GZIP and DEFLATE compression.
178         */
179        private boolean enableCompression = DEFAULT_ENABLE_COMPRESSION;
180
181
182        /**
183         * The default HTTP GZIP and DEFLATE compression enable policy.
184         */
185        public static final boolean DEFAULT_ENABLE_COMPRESSION = false;
186        
187        
188        /**
189         * If {@code true} self-signed certificates presented by the JSON-RPC 
190         * 2.0 server must be accepted.
191         */
192        private boolean trustAll = DEFAULT_TRUST_ALL;
193        
194        
195        /**
196         * The default policy for trusting self-signed certificates. Set to
197         * {@code false} (self-signed certificates not accepted).
198         */
199        public static final boolean DEFAULT_TRUST_ALL = false;
200
201
202        /**
203         * Creates a new default JSON-RPC 2.0 client session options instance.
204         *
205         * <p>The "Content-Type" (MIME) header value of HTTP POST requests will
206         * be set to "application/json". To change it use 
207         * {@link #setRequestContentType}.
208         *
209         * <p>"Origin" HTTP headers will not be added. To add one use
210         * {@link #setOrigin}.
211         * 
212         * <p>HTTP cookies will be ignored. To accept cookies, e.g. for 
213         * browser-like session handling, use {@link #acceptCookies}.
214         *
215         * <p>The allowed HTTP response content types are set to 
216         * "application/json" and "text/plain". To change them use
217         * {@link #setAllowedResponseContentTypes}.
218         *
219         * <p>The parse order of JSON object members in JSON-RPC 2.0 response
220         * results will not be preserved. To change this behaviour use
221         * {@link #preserveParseOrder}.
222         *
223         * <p>Strict 2.0 version checking will be performed. To ignore the
224         * JSON-RPC version attribute use {@link #ignoreVersion(boolean)}.
225         *
226         * <p>HTTP connect timeouts will be disabled. To specify a value use
227         * {@link #setConnectTimeout}.
228         *
229         * <p>HTTP read timeouts will be disabled. To specify a value use
230         * {@link #setReadTimeout}.
231         *
232         * <p>No proxy is used. To specify one use {@link #setProxy}.
233         *
234         * <p>HTTP response compression (GZIP or DEFLATE) is disabled. To 
235         * enable it use {@link #enableCompression(boolean)}.
236         *
237         * <p>Self-signed X.509 certificates presented by the JSON-RPC 2.0
238         * server will not be accepted. To relax certificate cheking use
239         * {@link #trustAllCerts}.
240         */
241        public JSONRPC2SessionOptions() {
242        
243                // check fields for default init values
244        }
245        
246        
247        /**
248         * Gets the value of the "Content-Type" (MIME) header for HTTP POST
249         * requests.
250         *
251         * @return The "Content-Type" (MIME) header value, {@code null} if the
252         *         header is not added to HTTP POST requests.
253         */
254        public String getRequestContentType() {
255        
256                return requestContentType;
257        }
258        
259        
260        /**
261         * Sets the value of the HTTP "Content-Type" (MIME) header. Use this 
262         * method if you wish to change the default "application/json" content 
263         * type.
264         *
265         * @param contentType The value of the "Content-Type" (MIME) header
266         *                    in HTTP POST requests, {@code null} to suppress
267         *                    the header.
268         */
269        public void setRequestContentType(final String contentType) {
270        
271                this.requestContentType = contentType;
272        }
273        
274        
275        /**
276         * Gets the value of the "Origin" HTTP header.
277         *
278         * <p>This header can be used to simulate Cross-Origin Resource Sharing
279         * (CORS) requests from a browser.
280         *
281         * @return The "Origin" header value, {@code null} if the header is not
282         *         added to HTTP requests.
283         */
284        public String getOrigin() {
285                
286                return origin;
287        }
288        
289        
290        /**
291         * Sets the value of the "Origin" HTTP header.
292         *
293         * <p>This header can be used to simulate Cross-Origin Resource Sharing
294         * (CORS) requests from a browser.
295         *
296         * @param origin The value of the "Origin" header in HTTP requests, 
297         *               {@code null} to suppress the header.
298         */
299        public void setOrigin(final String origin) {
300        
301                this.origin = origin;
302        }
303        
304        
305        /**
306         * Returns {@code true} if HTTP cookies are accepted, else 
307         * {@code false} if they are ignored.
308         *
309         * @return {@code true} if HTTP cookies are accepted, else 
310         *         {@code false}.
311         */
312        public boolean acceptCookies() {
313        
314                return acceptCookies;
315        }
316        
317        
318        /**
319         * Specifies whether to accept HTTP cookies contained in the server 
320         * response. Some JSON-RPC servers may use cookies instead of tokens
321         * passed through the JSON-RPC protocol itself to establish client 
322         * sessions.
323         *
324         * @param acceptCookies {@code true} to accept HTTP cookies, else
325         *                      {@code false} to ignore them.
326         */
327        public void acceptCookies(final boolean acceptCookies) {
328        
329                this.acceptCookies = acceptCookies;
330        }
331        
332        
333        /**
334         * Gets the allowed "Content-Type" (MIME) header values of HTTP 
335         * responses. 
336         *
337         * <p>The {@code JSONRPC2Session.send(...)} method will throw a
338         * {@link JSONRPC2SessionException#UNEXPECTED_CONTENT_TYPE} if the
339         * received HTTP response "Content-Type" (MIME) header value is not
340         * allowed.
341         *
342         * @return The allowed header values, if {@code null} any header value 
343         *         is allowed.
344         */
345        public String[] getAllowedResponseContentTypes() {
346        
347                return allowedResponseContentTypes;
348        }
349        
350        
351        /**
352         * Sets the allowed "Content-Type" (MIME) header values of HTTP 
353         * responses.
354         *
355         * <p>The {@code JSONRPC2Session.send(...)} method will throw a 
356         * {@link JSONRPC2SessionException#UNEXPECTED_CONTENT_TYPE} if the
357         * received HTTP response "Content-Type" (MIME) header value is not
358         * allowed.
359         *
360         * @param contentTypes The allowed header values, {@code null} to allow
361         *                     any header value.
362         */
363        public void setAllowedResponseContentTypes(final String[] contentTypes) {
364        
365                this.allowedResponseContentTypes = contentTypes;
366        }
367        
368        
369        /**
370         * Checks if the specified HTTP "Content-Type" (MIME) header value is 
371         * allowed.
372         *
373         * @param contentType The "Content-Type" (MIME) header value.
374         *
375         * @return {@code true} if the content type is allowed, else 
376         *         {@code false}.
377         */
378        public boolean isAllowedResponseContentType(final String contentType) {
379        
380                // Allow any?
381                if (allowedResponseContentTypes == null)
382                        return true;
383                
384                if (contentType == null)
385                        return false; // missing
386                
387                for (String t: allowedResponseContentTypes) {
388
389                        // Note: the content type may include optional parameters, 
390                        // which must be ignored during matching, e.g.
391                        // "application/json; charset=ISO-8859-1; ..."  
392                        if (contentType.matches("^" + Pattern.quote(t) + "(\\s|;|$)?.*"))
393                                return true;
394                }
395                
396                return false; // nothing matched
397        }
398        
399        
400        /**
401         * Returns {@code true} if the member order of parsed JSON objects in
402         * JSON-RPC 2.0 response results is preserved.
403         *
404         * @return {@code true} if the parse order of JSON object members is
405         *         preserved, else {@code false}.
406         */
407        public boolean preservesParseOrder() {
408        
409                return preserveObjectMemberOrder;
410        }
411        
412        
413        /**
414         * Controls the behaviour of the JSON parser when processing object
415         * members in JSON-RPC 2.0 response results. The default behaviour is
416         * to store the members in a {@code java.util.HashMap} in a 
417         * non-deterministic order. To preserve the original parse order pass a 
418         * boolean {@code true} to this method. Note that this will slow down 
419         * parsing and retrieval performance somewhat.
420         *
421         * @param preserve If {@code true} the parse order of JSON object 
422         *                 members will be preserved, else not.
423         */
424        public void preserveParseOrder(final boolean preserve) {
425        
426                preserveObjectMemberOrder = preserve;
427        }
428        
429        
430        /**
431         * Returns {@code true} if strict parsing of received JSON-RPC 2.0
432         * responses is disabled and the "jsonrpc" version attribute is not 
433         * checked for "2.0" equality. Returns {@code false} if received 
434         * JSON-RPC 2.0 responses must strictly conform to the JSON-RPC 2.0 
435         * specification.
436         *
437         * @return {@code true} if the {@code "jsonrpc":"2.0"} version 
438         *         attribute is ignored, {@code false} if parsing is strict.
439         */
440        public boolean ignoresVersion() {
441        
442                return ignoreVersion;
443        }
444        
445        
446        /**
447         * Controls the strictness of the JSON-RPC 2.0 response parser. The
448         * default behaviour is to check responses for strict compliance to
449         * the JSON-RPC 2.0 specification. By passing a boolean {@code true}
450         * parsing is relaxed and the "jsonrpc" version attribute will not be
451         * checked for "2.0" equality.
452         *
453         * @param ignore {@code true} to ignore the 2.0 {@code "jsonrpc":"2.0"} 
454         *               version attribute, {@code false} for strict parsing.
455         */
456        public void ignoreVersion(final boolean ignore) {
457        
458                ignoreVersion = ignore;
459        }
460        
461        
462        /**
463         * Specifies whether to parse non-standard attributes found in JSON-RPC 
464         * 2.0 responses. 
465         * 
466         * @param enable {@code true} to parse non-standard attributes, else 
467         *               {@code false}.
468         */
469        public void parseNonStdAttributes(final boolean enable) {
470        
471                parseNonStdAttributes = enable;
472        }
473        
474        
475        /**
476         * Returns {@code true} if non-standard attributes in JSON-RPC 2.0 
477         * responses are parsed. 
478         *
479         * @return {@code true} if non-standard attributes are parsed, else 
480         *         {@code false}.
481         */
482        public boolean parsesNonStdAttributes() {
483        
484                return parseNonStdAttributes;
485        }
486        
487        
488        /**
489         * Sets the HTTP connect timeout.
490         *
491         * @since 1.8
492         *
493         * @param timeout The HTTP connect timeout, in milliseconds. Zero
494         *                implies the option is disabled (timeout of infinity).
495         */
496        public void setConnectTimeout(final int timeout) {
497        
498                if (timeout < 0)
499                        throw new IllegalArgumentException("The HTTP connect timeout must be zero or positive");
500                
501                connectTimeout = timeout;
502        }
503        
504        
505        /**
506         * Gets the HTTP connect timeout.
507         *
508         * @since 1.8
509         *
510         * @return The HTTP connect timeout, in milliseconds. Zero implies the
511         *         option is disabled (timeout of infinity).
512         */
513        public int getConnectTimeout() {
514        
515                return connectTimeout;
516        }
517        
518        
519        /**
520         * Sets the HTTP read timeout.
521         *
522         * @since 1.8
523         *
524         * @param timeout The HTTP read timeout, in milliseconds. Zero implies
525         *                the option is disabled (timeout of infinity).
526         */
527        public void setReadTimeout(final int timeout) {
528        
529                if (timeout < 0)
530                        throw new IllegalArgumentException("The HTTP read timeout must be zero or positive");
531                
532                readTimeout = timeout;
533        }
534        
535        
536        /**
537         * Gets the HTTP read timeout.
538         *
539         * @since 1.8
540         *
541         * @return The HTTP read timeout, in milliseconds. Zero implies the 
542         *         option is disabled (timeout of infinity).
543         */
544        public int getReadTimeout() {
545        
546                return readTimeout;
547        }
548
549
550        /**
551         * Sets an HTTP proxy.
552         *
553         * @since 1.10
554         *
555         * @param proxy The HTTP proxy to use, {@code null} if none.
556         */
557        public void setProxy(final Proxy proxy) {
558
559                this.proxy = proxy;
560        }
561
562
563        /**
564         * Gets the HTTP proxy.
565         *
566         * @since 1.10
567         *
568         * @return The HTTP proxy to use, {@code null} if none.
569         */
570        public Proxy getProxy() {
571
572                return proxy;
573        }
574
575
576        /**
577         * Enables or disables HTTP response compression using GZIP or DEFLATE
578         * content encoding. If compression is enabled but the HTTP server 
579         * doesn't support compression this setting will have no effect.
580         *
581         * @param enable If {@code true} HTTP compression will be enabled, 
582         *               else compression will be disabled.
583         */
584        public void enableCompression(final boolean enable) {
585
586                enableCompression = enable;
587        }
588
589
590        /**
591         * Checks if HTTP response compression using GZIP or DEFLATE content 
592         * encoding is enabled or disabled. If compression is enabled but the 
593         * HTTP server doesn't support compression this setting will have no 
594         * effect.
595         *
596         * @return {@code true} if HTTP compression is enabled, else 
597         *         {@code false}.
598         */
599        public boolean enableCompression() {
600
601                return enableCompression;
602        }
603        
604        
605        /**
606         * Controls checking of X.509 certificates presented by the server when
607         * establishing a secure HTTPS connection. The default behaviour is to 
608         * accept only certicates issued by a trusted certificate authority 
609         * (CA), as determined by the default Java trust store. By passing a
610         * boolean {@code false} this security check is disabled and all 
611         * certificates will be trusted, including self-signed ones. Use this
612         * for testing and development purposes only.
613         *
614         * @param trustAll If {@code true} all X.509 certificates presented by 
615         *                 the web server will be trusted, including self-signed
616         *                 ones. If {@code false} the default security policy
617         *                 will be restored.
618         */
619        public void trustAllCerts(final boolean trustAll) {
620        
621                this.trustAll = trustAll;
622        }
623        
624        
625        /**
626         * Returns {@code true} if all X.509 certificates presented by the web
627         * server will be trusted, including self-signed ones. If {@code false} 
628         * the default security policy applies.
629         *
630         * @return {@code true} if all X.509 certificates are trusted, else
631         *         {@code false}.
632         */
633        public boolean trustsAllCerts() {
634        
635                return trustAll;
636        }
637}