001    package com.thetransactioncompany.jsonrpc2.client;
002    
003    
004    import java.net.Proxy;
005    
006    import 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     */
043    public 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    }