THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE +PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR +DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS +AGREEMENT.
+ +1. DEFINITIONS
+ +"Contribution" means:
+ +a) in the case of the initial Contributor, the initial +code and documentation distributed under this Agreement, and
+b) in the case of each subsequent Contributor:
+i) changes to the Program, and
+ii) additions to the Program;
+where such changes and/or additions to the Program +originate from and are distributed by that particular Contributor. A +Contribution 'originates' from a Contributor if it was added to the +Program by such Contributor itself or anyone acting on such +Contributor's behalf. Contributions do not include additions to the +Program which: (i) are separate modules of software distributed in +conjunction with the Program under their own license agreement, and (ii) +are not derivative works of the Program.
+ +"Contributor" means any person or entity that distributes +the Program.
+ +"Licensed Patents" mean patent claims licensable by a +Contributor which are necessarily infringed by the use or sale of its +Contribution alone or when combined with the Program.
+ +"Program" means the Contributions distributed in accordance +with this Agreement.
+ +"Recipient" means anyone who receives the Program under +this Agreement, including all Contributors.
+ +2. GRANT OF RIGHTS
+ +a) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free copyright license to reproduce, prepare derivative works +of, publicly display, publicly perform, distribute and sublicense the +Contribution of such Contributor, if any, and such derivative works, in +source code and object code form.
+ +b) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free patent license under Licensed Patents to make, use, sell, +offer to sell, import and otherwise transfer the Contribution of such +Contributor, if any, in source code and object code form. This patent +license shall apply to the combination of the Contribution and the +Program if, at the time the Contribution is added by the Contributor, +such addition of the Contribution causes such combination to be covered +by the Licensed Patents. The patent license shall not apply to any other +combinations which include the Contribution. No hardware per se is +licensed hereunder.
+ +c) Recipient understands that although each Contributor +grants the licenses to its Contributions set forth herein, no assurances +are provided by any Contributor that the Program does not infringe the +patent or other intellectual property rights of any other entity. Each +Contributor disclaims any liability to Recipient for claims brought by +any other entity based on infringement of intellectual property rights +or otherwise. As a condition to exercising the rights and licenses +granted hereunder, each Recipient hereby assumes sole responsibility to +secure any other intellectual property rights needed, if any. For +example, if a third party patent license is required to allow Recipient +to distribute the Program, it is Recipient's responsibility to acquire +that license before distributing the Program.
+ +d) Each Contributor represents that to its knowledge it +has sufficient copyright rights in its Contribution, if any, to grant +the copyright license set forth in this Agreement.
+ +3. REQUIREMENTS
+ +A Contributor may choose to distribute the Program in object code +form under its own license agreement, provided that:
+ +a) it complies with the terms and conditions of this +Agreement; and
+ +b) its license agreement:
+ +i) effectively disclaims on behalf of all Contributors +all warranties and conditions, express and implied, including warranties +or conditions of title and non-infringement, and implied warranties or +conditions of merchantability and fitness for a particular purpose;
+ +ii) effectively excludes on behalf of all Contributors +all liability for damages, including direct, indirect, special, +incidental and consequential damages, such as lost profits;
+ +iii) states that any provisions which differ from this +Agreement are offered by that Contributor alone and not by any other +party; and
+ +iv) states that source code for the Program is available +from such Contributor, and informs licensees how to obtain it in a +reasonable manner on or through a medium customarily used for software +exchange.
+ +When the Program is made available in source code form:
+ +a) it must be made available under this Agreement; and
+ +b) a copy of this Agreement must be included with each +copy of the Program.
+ +Contributors may not remove or alter any copyright notices contained +within the Program.
+ +Each Contributor must identify itself as the originator of its +Contribution, if any, in a manner that reasonably allows subsequent +Recipients to identify the originator of the Contribution.
+ +4. COMMERCIAL DISTRIBUTION
+ +Commercial distributors of software may accept certain +responsibilities with respect to end users, business partners and the +like. While this license is intended to facilitate the commercial use of +the Program, the Contributor who includes the Program in a commercial +product offering should do so in a manner which does not create +potential liability for other Contributors. Therefore, if a Contributor +includes the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and +indemnify every other Contributor ("Indemnified Contributor") +against any losses, damages and costs (collectively "Losses") +arising from claims, lawsuits and other legal actions brought by a third +party against the Indemnified Contributor to the extent caused by the +acts or omissions of such Commercial Contributor in connection with its +distribution of the Program in a commercial product offering. The +obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In +order to qualify, an Indemnified Contributor must: a) promptly notify +the Commercial Contributor in writing of such claim, and b) allow the +Commercial Contributor to control, and cooperate with the Commercial +Contributor in, the defense and any related settlement negotiations. The +Indemnified Contributor may participate in any such claim at its own +expense.
+ +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those +performance claims and warranties, and if a court requires any other +Contributor to pay any damages as a result, the Commercial Contributor +must pay those damages.
+ +5. NO WARRANTY
+ +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS +PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, +ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY +OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely +responsible for determining the appropriateness of using and +distributing the Program and assumes all risks associated with its +exercise of rights under this Agreement , including but not limited to +the risks and costs of program errors, compliance with applicable laws, +damage to or loss of data, programs or equipment, and unavailability or +interruption of operations.
+ +6. DISCLAIMER OF LIABILITY
+ +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT +NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING +WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR +DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED +HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ +7. GENERAL
+ +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further action +by the parties hereto, such provision shall be reformed to the minimum +extent necessary to make such provision valid and enforceable.
+ +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other +software or hardware) infringes such Recipient's patent(s), then such +Recipient's rights granted under Section 2(b) shall terminate as of the +date such litigation is filed.
+ +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of time +after becoming aware of such noncompliance. If all Recipient's rights +under this Agreement terminate, Recipient agrees to cease use and +distribution of the Program as soon as reasonably practicable. However, +Recipient's obligations under this Agreement and any licenses granted by +Recipient relating to the Program shall continue and survive.
+ +Everyone is permitted to copy and distribute copies of this +Agreement, but in order to avoid inconsistency the Agreement is +copyrighted and may only be modified in the following manner. The +Agreement Steward reserves the right to publish new versions (including +revisions) of this Agreement from time to time. No one other than the +Agreement Steward has the right to modify this Agreement. The Eclipse +Foundation is the initial Agreement Steward. The Eclipse Foundation may +assign the responsibility to serve as the Agreement Steward to a +suitable separate entity. Each new version of the Agreement will be +given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the +Agreement under which it was received. In addition, after a new version +of the Agreement is published, Contributor may elect to distribute the +Program (including its Contributions) under the new version. Except as +expressly stated in Sections 2(a) and 2(b) above, Recipient receives no +rights or licenses to the intellectual property of any Contributor under +this Agreement, whether expressly, by implication, estoppel or +otherwise. All rights in the Program not expressly granted under this +Agreement are reserved.
+ +This Agreement is governed by the laws of the State of New York and +the intellectual property laws of the United States of America. No party +to this Agreement will bring a legal action under this Agreement more +than one year after the cause of action arose. Each party waives its +rights to a jury trial in any resulting litigation.
+ + + + \ No newline at end of file diff --git a/com.eclipsesource.tabris.tracking.test/pom.xml b/com.eclipsesource.tabris.tracking.test/pom.xml new file mode 100644 index 0000000..f8f923a --- /dev/null +++ b/com.eclipsesource.tabris.tracking.test/pom.xml @@ -0,0 +1,57 @@ + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE +PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR +DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS +AGREEMENT.
+ +1. DEFINITIONS
+ +"Contribution" means:
+ +a) in the case of the initial Contributor, the initial +code and documentation distributed under this Agreement, and
+b) in the case of each subsequent Contributor:
+i) changes to the Program, and
+ii) additions to the Program;
+where such changes and/or additions to the Program +originate from and are distributed by that particular Contributor. A +Contribution 'originates' from a Contributor if it was added to the +Program by such Contributor itself or anyone acting on such +Contributor's behalf. Contributions do not include additions to the +Program which: (i) are separate modules of software distributed in +conjunction with the Program under their own license agreement, and (ii) +are not derivative works of the Program.
+ +"Contributor" means any person or entity that distributes +the Program.
+ +"Licensed Patents" mean patent claims licensable by a +Contributor which are necessarily infringed by the use or sale of its +Contribution alone or when combined with the Program.
+ +"Program" means the Contributions distributed in accordance +with this Agreement.
+ +"Recipient" means anyone who receives the Program under +this Agreement, including all Contributors.
+ +2. GRANT OF RIGHTS
+ +a) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free copyright license to reproduce, prepare derivative works +of, publicly display, publicly perform, distribute and sublicense the +Contribution of such Contributor, if any, and such derivative works, in +source code and object code form.
+ +b) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free patent license under Licensed Patents to make, use, sell, +offer to sell, import and otherwise transfer the Contribution of such +Contributor, if any, in source code and object code form. This patent +license shall apply to the combination of the Contribution and the +Program if, at the time the Contribution is added by the Contributor, +such addition of the Contribution causes such combination to be covered +by the Licensed Patents. The patent license shall not apply to any other +combinations which include the Contribution. No hardware per se is +licensed hereunder.
+ +c) Recipient understands that although each Contributor +grants the licenses to its Contributions set forth herein, no assurances +are provided by any Contributor that the Program does not infringe the +patent or other intellectual property rights of any other entity. Each +Contributor disclaims any liability to Recipient for claims brought by +any other entity based on infringement of intellectual property rights +or otherwise. As a condition to exercising the rights and licenses +granted hereunder, each Recipient hereby assumes sole responsibility to +secure any other intellectual property rights needed, if any. For +example, if a third party patent license is required to allow Recipient +to distribute the Program, it is Recipient's responsibility to acquire +that license before distributing the Program.
+ +d) Each Contributor represents that to its knowledge it +has sufficient copyright rights in its Contribution, if any, to grant +the copyright license set forth in this Agreement.
+ +3. REQUIREMENTS
+ +A Contributor may choose to distribute the Program in object code +form under its own license agreement, provided that:
+ +a) it complies with the terms and conditions of this +Agreement; and
+ +b) its license agreement:
+ +i) effectively disclaims on behalf of all Contributors +all warranties and conditions, express and implied, including warranties +or conditions of title and non-infringement, and implied warranties or +conditions of merchantability and fitness for a particular purpose;
+ +ii) effectively excludes on behalf of all Contributors +all liability for damages, including direct, indirect, special, +incidental and consequential damages, such as lost profits;
+ +iii) states that any provisions which differ from this +Agreement are offered by that Contributor alone and not by any other +party; and
+ +iv) states that source code for the Program is available +from such Contributor, and informs licensees how to obtain it in a +reasonable manner on or through a medium customarily used for software +exchange.
+ +When the Program is made available in source code form:
+ +a) it must be made available under this Agreement; and
+ +b) a copy of this Agreement must be included with each +copy of the Program.
+ +Contributors may not remove or alter any copyright notices contained +within the Program.
+ +Each Contributor must identify itself as the originator of its +Contribution, if any, in a manner that reasonably allows subsequent +Recipients to identify the originator of the Contribution.
+ +4. COMMERCIAL DISTRIBUTION
+ +Commercial distributors of software may accept certain +responsibilities with respect to end users, business partners and the +like. While this license is intended to facilitate the commercial use of +the Program, the Contributor who includes the Program in a commercial +product offering should do so in a manner which does not create +potential liability for other Contributors. Therefore, if a Contributor +includes the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and +indemnify every other Contributor ("Indemnified Contributor") +against any losses, damages and costs (collectively "Losses") +arising from claims, lawsuits and other legal actions brought by a third +party against the Indemnified Contributor to the extent caused by the +acts or omissions of such Commercial Contributor in connection with its +distribution of the Program in a commercial product offering. The +obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In +order to qualify, an Indemnified Contributor must: a) promptly notify +the Commercial Contributor in writing of such claim, and b) allow the +Commercial Contributor to control, and cooperate with the Commercial +Contributor in, the defense and any related settlement negotiations. The +Indemnified Contributor may participate in any such claim at its own +expense.
+ +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those +performance claims and warranties, and if a court requires any other +Contributor to pay any damages as a result, the Commercial Contributor +must pay those damages.
+ +5. NO WARRANTY
+ +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS +PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, +ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY +OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely +responsible for determining the appropriateness of using and +distributing the Program and assumes all risks associated with its +exercise of rights under this Agreement , including but not limited to +the risks and costs of program errors, compliance with applicable laws, +damage to or loss of data, programs or equipment, and unavailability or +interruption of operations.
+ +6. DISCLAIMER OF LIABILITY
+ +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT +NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING +WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR +DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED +HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ +7. GENERAL
+ +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further action +by the parties hereto, such provision shall be reformed to the minimum +extent necessary to make such provision valid and enforceable.
+ +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other +software or hardware) infringes such Recipient's patent(s), then such +Recipient's rights granted under Section 2(b) shall terminate as of the +date such litigation is filed.
+ +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of time +after becoming aware of such noncompliance. If all Recipient's rights +under this Agreement terminate, Recipient agrees to cease use and +distribution of the Program as soon as reasonably practicable. However, +Recipient's obligations under this Agreement and any licenses granted by +Recipient relating to the Program shall continue and survive.
+ +Everyone is permitted to copy and distribute copies of this +Agreement, but in order to avoid inconsistency the Agreement is +copyrighted and may only be modified in the following manner. The +Agreement Steward reserves the right to publish new versions (including +revisions) of this Agreement from time to time. No one other than the +Agreement Steward has the right to modify this Agreement. The Eclipse +Foundation is the initial Agreement Steward. The Eclipse Foundation may +assign the responsibility to serve as the Agreement Steward to a +suitable separate entity. Each new version of the Agreement will be +given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the +Agreement under which it was received. In addition, after a new version +of the Agreement is published, Contributor may elect to distribute the +Program (including its Contributions) under the new version. Except as +expressly stated in Sections 2(a) and 2(b) above, Recipient receives no +rights or licenses to the intellectual property of any Contributor under +this Agreement, whether expressly, by implication, estoppel or +otherwise. All rights in the Program not expressly granted under this +Agreement are reserved.
+ +This Agreement is governed by the laws of the State of New York and +the intellectual property laws of the United States of America. No party +to this Agreement will bring a legal action under this Agreement more +than one year after the cause of action arose. Each party waives its +rights to a jury trial in any resulting litigation.
+ + + + \ No newline at end of file diff --git a/com.eclipsesource.tabris.tracking/plugin.properties b/com.eclipsesource.tabris.tracking/plugin.properties new file mode 100644 index 0000000..8e26b91 --- /dev/null +++ b/com.eclipsesource.tabris.tracking/plugin.properties @@ -0,0 +1,13 @@ +############################################################################### +# Copyright (c) 2014 EclipseSource and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# EclipseSource - ongoing development +################################################################################ + +Bundle-Name = Tabris Tracking API +Bundle-Vendor = EclipseSource diff --git a/com.eclipsesource.tabris.tracking/pom.xml b/com.eclipsesource.tabris.tracking/pom.xml new file mode 100644 index 0000000..67f55f2 --- /dev/null +++ b/com.eclipsesource.tabris.tracking/pom.xml @@ -0,0 +1,81 @@ + + + ++ * Each instance supports making a single request and cannot be reused for + * further requests. + */ +public class HttpRequest { + + /** + * 'UTF-8' charset name + */ + public static final String CHARSET_UTF8 = "UTF-8"; + + /** + * 'application/x-www-form-urlencoded' content type header value + */ + public static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded"; + + /** + * 'application/json' content type header value + */ + public static final String CONTENT_TYPE_JSON = "application/json"; + + /** + * 'gzip' encoding header value + */ + public static final String ENCODING_GZIP = "gzip"; + + /** + * 'Accept' header name + */ + public static final String HEADER_ACCEPT = "Accept"; + + /** + * 'Accept-Charset' header name + */ + public static final String HEADER_ACCEPT_CHARSET = "Accept-Charset"; + + /** + * 'Accept-Encoding' header name + */ + public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding"; + + /** + * 'Authorization' header name + */ + public static final String HEADER_AUTHORIZATION = "Authorization"; + + /** + * 'Cache-Control' header name + */ + public static final String HEADER_CACHE_CONTROL = "Cache-Control"; + + /** + * 'Content-Encoding' header name + */ + public static final String HEADER_CONTENT_ENCODING = "Content-Encoding"; + + /** + * 'Content-Length' header name + */ + public static final String HEADER_CONTENT_LENGTH = "Content-Length"; + + /** + * 'Content-Type' header name + */ + public static final String HEADER_CONTENT_TYPE = "Content-Type"; + + /** + * 'Date' header name + */ + public static final String HEADER_DATE = "Date"; + + /** + * 'ETag' header name + */ + public static final String HEADER_ETAG = "ETag"; + + /** + * 'Expires' header name + */ + public static final String HEADER_EXPIRES = "Expires"; + + /** + * 'If-None-Match' header name + */ + public static final String HEADER_IF_NONE_MATCH = "If-None-Match"; + + /** + * 'Last-Modified' header name + */ + public static final String HEADER_LAST_MODIFIED = "Last-Modified"; + + /** + * 'Location' header name + */ + public static final String HEADER_LOCATION = "Location"; + + /** + * 'Proxy-Authorization' header name + */ + public static final String HEADER_PROXY_AUTHORIZATION = "Proxy-Authorization"; + + /** + * 'Referer' header name + */ + public static final String HEADER_REFERER = "Referer"; + + /** + * 'Server' header name + */ + public static final String HEADER_SERVER = "Server"; + + /** + * 'User-Agent' header name + */ + public static final String HEADER_USER_AGENT = "User-Agent"; + + /** + * 'DELETE' request method + */ + public static final String METHOD_DELETE = "DELETE"; + + /** + * 'GET' request method + */ + public static final String METHOD_GET = "GET"; + + /** + * 'HEAD' request method + */ + public static final String METHOD_HEAD = "HEAD"; + + /** + * 'OPTIONS' options method + */ + public static final String METHOD_OPTIONS = "OPTIONS"; + + /** + * 'POST' request method + */ + public static final String METHOD_POST = "POST"; + + /** + * 'PUT' request method + */ + public static final String METHOD_PUT = "PUT"; + + /** + * 'TRACE' request method + */ + public static final String METHOD_TRACE = "TRACE"; + + /** + * 'charset' header value parameter + */ + public static final String PARAM_CHARSET = "charset"; + + private static final String BOUNDARY = "00content0boundary00"; + + private static final String CONTENT_TYPE_MULTIPART = "multipart/form-data; boundary=" + + BOUNDARY; + + private static final String CRLF = "\r\n"; + + private static final String[] EMPTY_STRINGS = new String[0]; + + private static SSLSocketFactory TRUSTED_FACTORY; + + private static HostnameVerifier TRUSTED_VERIFIER; + + private static String getValidCharset(final String charset) { + if (charset != null && charset.length() > 0) + return charset; + return CHARSET_UTF8; + } + + private static SSLSocketFactory getTrustedFactory() + throws HttpRequestException { + if (TRUSTED_FACTORY == null) { + final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) { + // Intentionally left blank + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) { + // Intentionally left blank + } + } }; + try { + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, trustAllCerts, new SecureRandom()); + TRUSTED_FACTORY = context.getSocketFactory(); + } catch (GeneralSecurityException e) { + IOException ioException = new IOException( + "Security exception configuring SSL context"); + ioException.initCause(e); + throw new HttpRequestException(ioException); + } + } + + return TRUSTED_FACTORY; + } + + private static HostnameVerifier getTrustedVerifier() { + if (TRUSTED_VERIFIER == null) + TRUSTED_VERIFIER = new HostnameVerifier() { + + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + + return TRUSTED_VERIFIER; + } + + private static StringBuilder addPathSeparator(final String baseUrl, + final StringBuilder result) { + // Add trailing slash if the base URL doesn't have any path segments. + // + // The following test is checking for the last slash not being part of + // the protocol to host separator: '://'. + if (baseUrl.indexOf(':') + 2 == baseUrl.lastIndexOf('/')) + result.append('/'); + return result; + } + + private static StringBuilder addParamPrefix(final String baseUrl, + final StringBuilder result) { + // Add '?' if missing and add '&' if params already exist in base url + final int queryStart = baseUrl.indexOf('?'); + final int lastChar = result.length() - 1; + if (queryStart == -1) + result.append('?'); + else if (queryStart < lastChar && baseUrl.charAt(lastChar) != '&') + result.append('&'); + return result; + } + + /** + * Creates {@link HttpURLConnection HTTP connections} for + * {@link URL urls}. + */ + public interface ConnectionFactory { + /** + * Open an {@link HttpURLConnection} for the specified {@link URL}. + * + * @throws IOException + */ + HttpURLConnection create(URL url) throws IOException; + + /** + * Open an {@link HttpURLConnection} for the specified {@link URL} + * and {@link Proxy}. + * + * @throws IOException + */ + HttpURLConnection create(URL url, Proxy proxy) throws IOException; + + /** + * A {@link ConnectionFactory} which uses the built-in + * {@link URL#openConnection()} + */ + ConnectionFactory DEFAULT = new ConnectionFactory() { + @Override + public HttpURLConnection create(URL url) throws IOException { + return (HttpURLConnection) url.openConnection(); + } + + @Override + public HttpURLConnection create(URL url, Proxy proxy) throws IOException { + return (HttpURLConnection) url.openConnection(proxy); + } + }; + } + + private static ConnectionFactory CONNECTION_FACTORY = ConnectionFactory.DEFAULT; + + /** + * Specify the {@link ConnectionFactory} used to create new requests. + */ + public static void setConnectionFactory(final ConnectionFactory connectionFactory) { + if (connectionFactory == null) + CONNECTION_FACTORY = ConnectionFactory.DEFAULT; + else + CONNECTION_FACTORY = connectionFactory; + } + + /** + * Callback interface for reporting upload progress for a request. + */ + public interface UploadProgress { + /** + * Callback invoked as data is uploaded by the request. + * + * @param uploaded The number of bytes already uploaded + * @param total The total number of bytes that will be uploaded or -1 if + * the length is unknown. + */ + void onUpload(long uploaded, long total); + + UploadProgress DEFAULT = new UploadProgress() { + @Override + public void onUpload(long uploaded, long total) { + } + }; + } + + /** + *
+ * Encodes and decodes to and from Base64 notation. + *
+ *+ * I am placing this code in the Public Domain. Do with it as you will. This + * software comes with no guarantees or warranties but with plenty of + * well-wishing instead! Please visit http://iharder.net/base64 periodically + * to check for updates or to contribute improvements. + *
+ * + * @author Robert Harder + * @author rob@iharder.net + * @version 2.3.7 + */ + public static class Base64 { + + /** The equals sign (=) as a byte. */ + private final static byte EQUALS_SIGN = (byte) '='; + + /** Preferred encoding. */ + private final static String PREFERRED_ENCODING = "US-ASCII"; + + /** The 64 valid Base64 values. */ + private final static byte[] _STANDARD_ALPHABET = { (byte) 'A', (byte) 'B', + (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', + (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', + (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', + (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', + (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', + (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', + (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', + (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', + (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', + (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', + (byte) '+', (byte) '/' }; + + /** Defeats instantiation. */ + private Base64() { + } + + /** + *+ * Encodes up to three bytes of the array source and writes the + * resulting four Base64 bytes to destination. The source and + * destination arrays can be manipulated anywhere along their length by + * specifying srcOffset and destOffset. This method + * does not check to make sure your arrays are large enough to accomodate + * srcOffset + 3 for the source array or + * destOffset + 4 for the destination array. The + * actual number of significant bytes in your array is given by + * numSigBytes. + *
+ *+ * This is the lowest level of the encoding methods with all possible + * parameters. + *
+ * + * @param source + * the array to convert + * @param srcOffset + * the index where conversion begins + * @param numSigBytes + * the number of significant bytes in your array + * @param destination + * the array to hold the conversion + * @param destOffset + * the index where output will be put + * @return the destination array + * @since 1.3 + */ + private static byte[] encode3to4(byte[] source, int srcOffset, + int numSigBytes, byte[] destination, int destOffset) { + + byte[] ALPHABET = _STANDARD_ALPHABET; + + int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) + | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) + | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); + + switch (numSigBytes) { + case 3: + destination[destOffset] = ALPHABET[(inBuff >>> 18)]; + destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; + destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f]; + return destination; + + case 2: + destination[destOffset] = ALPHABET[(inBuff >>> 18)]; + destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; + destination[destOffset + 3] = EQUALS_SIGN; + return destination; + + case 1: + destination[destOffset] = ALPHABET[(inBuff >>> 18)]; + destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = EQUALS_SIGN; + destination[destOffset + 3] = EQUALS_SIGN; + return destination; + + default: + return destination; + } + } + + /** + * Encode string as a byte array in Base64 annotation. + * + * @param string + * @return The Base64-encoded data as a string + */ + public static String encode(String string) { + byte[] bytes; + try { + bytes = string.getBytes(PREFERRED_ENCODING); + } catch (UnsupportedEncodingException e) { + bytes = string.getBytes(); + } + return encodeBytes(bytes); + } + + /** + * Encodes a byte array into Base64 notation. + * + * @param source + * The data to convert + * @return The Base64-encoded data as a String + * @throws NullPointerException + * if source array is null + * @throws IllegalArgumentException + * if source array, offset, or length are invalid + * @since 2.0 + */ + public static String encodeBytes(byte[] source) { + return encodeBytes(source, 0, source.length); + } + + /** + * Encodes a byte array into Base64 notation. + * + * @param source + * The data to convert + * @param off + * Offset in array where conversion should begin + * @param len + * Length of data to convert + * @return The Base64-encoded data as a String + * @throws NullPointerException + * if source array is null + * @throws IllegalArgumentException + * if source array, offset, or length are invalid + * @since 2.0 + */ + public static String encodeBytes(byte[] source, int off, int len) { + byte[] encoded = encodeBytesToBytes(source, off, len); + try { + return new String(encoded, PREFERRED_ENCODING); + } catch (UnsupportedEncodingException uue) { + return new String(encoded); + } + } + + /** + * Similar to {@link #encodeBytes(byte[], int, int)} but returns a byte + * array instead of instantiating a String. This is more efficient if you're + * working with I/O streams and have large data sets to encode. + * + * + * @param source + * The data to convert + * @param off + * Offset in array where conversion should begin + * @param len + * Length of data to convert + * @return The Base64-encoded data as a String if there is an error + * @throws NullPointerException + * if source array is null + * @throws IllegalArgumentException + * if source array, offset, or length are invalid + * @since 2.3.1 + */ + public static byte[] encodeBytesToBytes(byte[] source, int off, int len) { + + if (source == null) + throw new NullPointerException("Cannot serialize a null array."); + + if (off < 0) + throw new IllegalArgumentException("Cannot have negative offset: " + + off); + + if (len < 0) + throw new IllegalArgumentException("Cannot have length offset: " + len); + + if (off + len > source.length) + throw new IllegalArgumentException( + String + .format( + "Cannot have offset of %d and length of %d with array of length %d", + Integer.valueOf( off ), Integer.valueOf( len ), Integer.valueOf( source.length ))); + + // Bytes needed for actual encoding + int encLen = (len / 3) * 4 + (len % 3 > 0 ? 4 : 0); + + byte[] outBuff = new byte[encLen]; + + int d = 0; + int e = 0; + int len2 = len - 2; + for (; d < len2; d += 3, e += 4) + encode3to4(source, d + off, 3, outBuff, e); + + if (d < len) { + encode3to4(source, d + off, len - d, outBuff, e); + e += 4; + } + + if (e <= outBuff.length - 1) { + byte[] finalOut = new byte[e]; + System.arraycopy(outBuff, 0, finalOut, 0, e); + return finalOut; + } + return outBuff; + } + } + + /** + * HTTP request exception whose cause is always an {@link IOException} + */ + public static class HttpRequestException extends RuntimeException { + + private static final long serialVersionUID = -1170466989781746231L; + + /** + * Create a new HttpRequestException with the given cause + * + * @param cause + */ + public HttpRequestException(final IOException cause) { + super(cause); + } + + /** + * Get {@link IOException} that triggered this request exception + * + * @return {@link IOException} cause + */ + @Override + public IOException getCause() { + return (IOException) super.getCause(); + } + } + + /** + * Operation that handles executing a callback once complete and handling + * nested exceptions + * + * @param+ * This method ensures the path and query segments of the URL are properly + * encoded such as ' ' characters being encoded to '%20' or any UTF-8 + * characters that are non-ASCII. No encoding of URLs is done by default by + * the {@link HttpRequest} constructors and so if URL encoding is needed this + * method should be called before calling the {@link HttpRequest} constructor. + * + * @param url + * @return encoded URL + * @throws HttpRequestException + */ + public static String encode(final CharSequence url) + throws HttpRequestException { + URL parsed; + try { + parsed = new URL(url.toString()); + } catch (IOException e) { + throw new HttpRequestException(e); + } + + String host = parsed.getHost(); + int port = parsed.getPort(); + if (port != -1) + host = host + ':' + Integer.toString(port); + + try { + String encoded = new URI(parsed.getProtocol(), host, parsed.getPath(), + parsed.getQuery(), null).toASCIIString(); + int paramsStart = encoded.indexOf('?'); + if (paramsStart > 0 && paramsStart + 1 < encoded.length()) + encoded = encoded.substring(0, paramsStart + 1) + + encoded.substring(paramsStart + 1).replace("+", "%2B"); + return encoded; + } catch (URISyntaxException e) { + IOException io = new IOException("Parsing URI failed"); + io.initCause(e); + throw new HttpRequestException(io); + } + } + + /** + * Append given map as query parameters to the base URL + *
+ * Each map entry's key will be a parameter name and the value's + * {@link Object#toString()} will be the parameter value. + * + * @param url + * @param params + * @return URL with appended query params + */ + public static String append(final CharSequence url, final Map, ?> params) { + final String baseUrl = url.toString(); + if (params == null || params.isEmpty()) + return baseUrl; + + final StringBuilder result = new StringBuilder(baseUrl); + + addPathSeparator(baseUrl, result); + addParamPrefix(baseUrl, result); + + Entry, ?> entry; + Object value; + Iterator> iterator = params.entrySet().iterator(); + entry = (Entry, ?>) iterator.next(); + result.append(entry.getKey().toString()); + result.append('='); + value = entry.getValue(); + if (value != null) + result.append(value); + + while (iterator.hasNext()) { + result.append('&'); + entry = (Entry, ?>) iterator.next(); + result.append(entry.getKey().toString()); + result.append('='); + value = entry.getValue(); + if (value != null) + result.append(value); + } + + return result.toString(); + } + + /** + * Append given name/value pairs as query parameters to the base URL + *
+ * The params argument is interpreted as a sequence of name/value pairs so the + * given number of params must be divisible by 2. + * + * @param url + * @param params + * name/value pairs + * @return URL with appended query params + */ + public static String append(final CharSequence url, final Object... params) { + final String baseUrl = url.toString(); + if (params == null || params.length == 0) + return baseUrl; + + if (params.length % 2 != 0) + throw new IllegalArgumentException( + "Must specify an even number of parameter names/values"); + + final StringBuilder result = new StringBuilder(baseUrl); + + addPathSeparator(baseUrl, result); + addParamPrefix(baseUrl, result); + + Object value; + result.append(params[0]); + result.append('='); + value = params[1]; + if (value != null) + result.append(value); + + for (int i = 2; i < params.length; i += 2) { + result.append('&'); + result.append(params[i]); + result.append('='); + value = params[i + 1]; + if (value != null) + result.append(value); + } + + return result.toString(); + } + + /** + * Start a 'GET' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest get(final CharSequence url) + throws HttpRequestException { + return new HttpRequest(url, METHOD_GET); + } + + /** + * Start a 'GET' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest get(final URL url) throws HttpRequestException { + return new HttpRequest(url, METHOD_GET); + } + + /** + * Start a 'GET' request to the given URL along with the query params + * + * @param baseUrl + * @param params + * The query parameters to include as part of the baseUrl + * @param encode + * true to encode the full URL + * + * @see #append(CharSequence, Map) + * @see #encode(CharSequence) + * + * @return request + */ + public static HttpRequest get(final CharSequence baseUrl, + final Map, ?> params, final boolean encode) { + String url = append(baseUrl, params); + return get(encode ? encode(url) : url); + } + + /** + * Start a 'GET' request to the given URL along with the query params + * + * @param baseUrl + * @param encode + * true to encode the full URL + * @param params + * the name/value query parameter pairs to include as part of the + * baseUrl + * + * @see #append(CharSequence, String...) + * @see #encode(CharSequence) + * + * @return request + */ + public static HttpRequest get(final CharSequence baseUrl, + final boolean encode, final Object... params) { + String url = append(baseUrl, params); + return get(encode ? encode(url) : url); + } + + /** + * Start a 'POST' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest post(final CharSequence url) + throws HttpRequestException { + return new HttpRequest(url, METHOD_POST); + } + + /** + * Start a 'POST' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest post(final URL url) throws HttpRequestException { + return new HttpRequest(url, METHOD_POST); + } + + /** + * Start a 'POST' request to the given URL along with the query params + * + * @param baseUrl + * @param params + * the query parameters to include as part of the baseUrl + * @param encode + * true to encode the full URL + * + * @see #append(CharSequence, Map) + * @see #encode(CharSequence) + * + * @return request + */ + public static HttpRequest post(final CharSequence baseUrl, + final Map, ?> params, final boolean encode) { + String url = append(baseUrl, params); + return post(encode ? encode(url) : url); + } + + /** + * Start a 'POST' request to the given URL along with the query params + * + * @param baseUrl + * @param encode + * true to encode the full URL + * @param params + * the name/value query parameter pairs to include as part of the + * baseUrl + * + * @see #append(CharSequence, String...) + * @see #encode(CharSequence) + * + * @return request + */ + public static HttpRequest post(final CharSequence baseUrl, + final boolean encode, final Object... params) { + String url = append(baseUrl, params); + return post(encode ? encode(url) : url); + } + + /** + * Start a 'PUT' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest put(final CharSequence url) + throws HttpRequestException { + return new HttpRequest(url, METHOD_PUT); + } + + /** + * Start a 'PUT' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest put(final URL url) throws HttpRequestException { + return new HttpRequest(url, METHOD_PUT); + } + + /** + * Start a 'PUT' request to the given URL along with the query params + * + * @param baseUrl + * @param params + * the query parameters to include as part of the baseUrl + * @param encode + * true to encode the full URL + * + * @see #append(CharSequence, Map) + * @see #encode(CharSequence) + * + * @return request + */ + public static HttpRequest put(final CharSequence baseUrl, + final Map, ?> params, final boolean encode) { + String url = append(baseUrl, params); + return put(encode ? encode(url) : url); + } + + /** + * Start a 'PUT' request to the given URL along with the query params + * + * @param baseUrl + * @param encode + * true to encode the full URL + * @param params + * the name/value query parameter pairs to include as part of the + * baseUrl + * + * @see #append(CharSequence, String...) + * @see #encode(CharSequence) + * + * @return request + */ + public static HttpRequest put(final CharSequence baseUrl, + final boolean encode, final Object... params) { + String url = append(baseUrl, params); + return put(encode ? encode(url) : url); + } + + /** + * Start a 'DELETE' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest delete(final CharSequence url) + throws HttpRequestException { + return new HttpRequest(url, METHOD_DELETE); + } + + /** + * Start a 'DELETE' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest delete(final URL url) throws HttpRequestException { + return new HttpRequest(url, METHOD_DELETE); + } + + /** + * Start a 'DELETE' request to the given URL along with the query params + * + * @param baseUrl + * @param params + * The query parameters to include as part of the baseUrl + * @param encode + * true to encode the full URL + * + * @see #append(CharSequence, Map) + * @see #encode(CharSequence) + * + * @return request + */ + public static HttpRequest delete(final CharSequence baseUrl, + final Map, ?> params, final boolean encode) { + String url = append(baseUrl, params); + return delete(encode ? encode(url) : url); + } + + /** + * Start a 'DELETE' request to the given URL along with the query params + * + * @param baseUrl + * @param encode + * true to encode the full URL + * @param params + * the name/value query parameter pairs to include as part of the + * baseUrl + * + * @see #append(CharSequence, String...) + * @see #encode(CharSequence) + * + * @return request + */ + public static HttpRequest delete(final CharSequence baseUrl, + final boolean encode, final Object... params) { + String url = append(baseUrl, params); + return delete(encode ? encode(url) : url); + } + + /** + * Start a 'HEAD' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest head(final CharSequence url) + throws HttpRequestException { + return new HttpRequest(url, METHOD_HEAD); + } + + /** + * Start a 'HEAD' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest head(final URL url) throws HttpRequestException { + return new HttpRequest(url, METHOD_HEAD); + } + + /** + * Start a 'HEAD' request to the given URL along with the query params + * + * @param baseUrl + * @param params + * The query parameters to include as part of the baseUrl + * @param encode + * true to encode the full URL + * + * @see #append(CharSequence, Map) + * @see #encode(CharSequence) + * + * @return request + */ + public static HttpRequest head(final CharSequence baseUrl, + final Map, ?> params, final boolean encode) { + String url = append(baseUrl, params); + return head(encode ? encode(url) : url); + } + + /** + * Start a 'GET' request to the given URL along with the query params + * + * @param baseUrl + * @param encode + * true to encode the full URL + * @param params + * the name/value query parameter pairs to include as part of the + * baseUrl + * + * @see #append(CharSequence, String...) + * @see #encode(CharSequence) + * + * @return request + */ + public static HttpRequest head(final CharSequence baseUrl, + final boolean encode, final Object... params) { + String url = append(baseUrl, params); + return head(encode ? encode(url) : url); + } + + /** + * Start an 'OPTIONS' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest options(final CharSequence url) + throws HttpRequestException { + return new HttpRequest(url, METHOD_OPTIONS); + } + + /** + * Start an 'OPTIONS' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest options(final URL url) throws HttpRequestException { + return new HttpRequest(url, METHOD_OPTIONS); + } + + /** + * Start a 'TRACE' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest trace(final CharSequence url) + throws HttpRequestException { + return new HttpRequest(url, METHOD_TRACE); + } + + /** + * Start a 'TRACE' request to the given URL + * + * @param url + * @return request + * @throws HttpRequestException + */ + public static HttpRequest trace(final URL url) throws HttpRequestException { + return new HttpRequest(url, METHOD_TRACE); + } + + /** + * Set the 'http.keepAlive' property to the given value. + *
+ * This setting will apply to all requests. + * + * @param keepAlive + */ + public static void keepAlive(final boolean keepAlive) { + setProperty("http.keepAlive", Boolean.toString(keepAlive)); + } + + /** + * Set the 'http.maxConnections' property to the given value. + *
+ * This setting will apply to all requests. + * + * @param maxConnections + */ + public static void maxConnections(final int maxConnections) { + setProperty("http.maxConnections", Integer.toString(maxConnections)); + } + + /** + * Set the 'http.proxyHost' & 'https.proxyHost' properties to the given host + * value. + *
+ * This setting will apply to all requests. + * + * @param host + */ + public static void proxyHost(final String host) { + setProperty("http.proxyHost", host); + setProperty("https.proxyHost", host); + } + + /** + * Set the 'http.proxyPort' & 'https.proxyPort' properties to the given port + * number. + *
+ * This setting will apply to all requests. + * + * @param port + */ + public static void proxyPort(final int port) { + final String portValue = Integer.toString(port); + setProperty("http.proxyPort", portValue); + setProperty("https.proxyPort", portValue); + } + + /** + * Set the 'http.nonProxyHosts' property to the given host values. + *
+ * Hosts will be separated by a '|' character. + *
+ * This setting will apply to all requests. + * + * @param hosts + */ + public static void nonProxyHosts(final String... hosts) { + if (hosts != null && hosts.length > 0) { + StringBuilder separated = new StringBuilder(); + int last = hosts.length - 1; + for (int i = 0; i < last; i++) + separated.append(hosts[i]).append('|'); + separated.append(hosts[last]); + setProperty("http.nonProxyHosts", separated.toString()); + } else + setProperty("http.nonProxyHosts", null); + } + + /** + * Set property to given value. + *
+ * Specifying a null value will cause the property to be cleared
+ *
+ * @param name
+ * @param value
+ * @return previous value
+ */
+ private static String setProperty(final String name, final String value) {
+ final PrivilegedAction
+ * The default value of this setting is
+ * This size is also used for send and receive buffers created for both char
+ * and byte arrays
+ *
+ * The default buffer size is 8,192 bytes
+ *
+ * @param size
+ * @return this request
+ */
+ public HttpRequest bufferSize(final int size) {
+ if (size < 1)
+ throw new IllegalArgumentException("Size must be greater than zero");
+ bufferSize = size;
+ return this;
+ }
+
+ /**
+ * Get the configured buffer size
+ *
+ * The default buffer size is 8,192 bytes
+ *
+ * @return buffer size
+ */
+ public int bufferSize() {
+ return bufferSize;
+ }
+
+ /**
+ * Set whether or not the response body should be automatically uncompressed
+ * when read from.
+ *
+ * This will only affect requests that have the 'Content-Encoding' response
+ * header set to 'gzip'.
+ *
+ * This causes all receive methods to use a {@link GZIPInputStream} when
+ * applicable so that higher level streams and readers can read the data
+ * uncompressed.
+ *
+ * Setting this option does not cause any request headers to be set
+ * automatically so {@link #acceptGzipEncoding()} should be used in
+ * conjunction with this setting to tell the server to gzip the response.
+ *
+ * @param uncompress
+ * @return this request
+ */
+ public HttpRequest uncompress(final boolean uncompress) {
+ this.uncompress = uncompress;
+ return this;
+ }
+
+ /**
+ * Create byte array output stream
+ *
+ * @return stream
+ */
+ protected ByteArrayOutputStream byteStream() {
+ final int size = contentLength();
+ if (size > 0)
+ return new ByteArrayOutputStream(size);
+ return new ByteArrayOutputStream();
+ }
+
+ /**
+ * Get response as {@link String} in given character set
+ *
+ * This will fall back to using the UTF-8 character set if the given charset
+ * is null
+ *
+ * @param charset
+ * @return string
+ * @throws HttpRequestException
+ */
+ public String body(final String charset) throws HttpRequestException {
+ final ByteArrayOutputStream output = byteStream();
+ try {
+ copy(buffer(), output);
+ return output.toString(getValidCharset(charset));
+ } catch (IOException e) {
+ throw new HttpRequestException(e);
+ }
+ }
+
+ /**
+ * Get response as {@link String} using character set returned from
+ * {@link #charset()}
+ *
+ * @return string
+ * @throws HttpRequestException
+ */
+ public String body() throws HttpRequestException {
+ return body(charset());
+ }
+
+ /**
+ * Get the response body as a {@link String} and set it as the value of the
+ * given reference.
+ *
+ * @param output
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest body(final AtomicReference
+ * This will fall back to using the UTF-8 character set if the given charset
+ * is null
+ *
+ * @param charset
+ * @return reader
+ * @throws HttpRequestException
+ */
+ public InputStreamReader reader(final String charset)
+ throws HttpRequestException {
+ try {
+ return new InputStreamReader(stream(), getValidCharset(charset));
+ } catch (UnsupportedEncodingException e) {
+ throw new HttpRequestException(e);
+ }
+ }
+
+ /**
+ * Get reader to response body using the character set returned from
+ * {@link #charset()}
+ *
+ * @return reader
+ * @throws HttpRequestException
+ */
+ public InputStreamReader reader() throws HttpRequestException {
+ return reader(charset());
+ }
+
+ /**
+ * Get buffered reader to response body using the given character set r and
+ * the configured buffer size
+ *
+ *
+ * @see #bufferSize(int)
+ * @param charset
+ * @return reader
+ * @throws HttpRequestException
+ */
+ public BufferedReader bufferedReader(final String charset)
+ throws HttpRequestException {
+ return new BufferedReader(reader(charset), bufferSize);
+ }
+
+ /**
+ * Get buffered reader to response body using the character set returned from
+ * {@link #charset()} and the configured buffer size
+ *
+ * @see #bufferSize(int)
+ * @return reader
+ * @throws HttpRequestException
+ */
+ public BufferedReader bufferedReader() throws HttpRequestException {
+ return bufferedReader(charset());
+ }
+
+ /**
+ * Stream response body to file
+ *
+ * @param file
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest receive(final File file) throws HttpRequestException {
+ final OutputStream output;
+ try {
+ output = new BufferedOutputStream(new FileOutputStream(file), bufferSize);
+ } catch (FileNotFoundException e) {
+ throw new HttpRequestException(e);
+ }
+ return new CloseOperation
+ * This will be all key=value pairs after the first ';' that are separated by
+ * a ';'
+ *
+ * @param headerName
+ * @return non-null but possibly empty map of parameter headers
+ */
+ public Map
+ * The given stream will be closed once sending completes
+ *
+ * @param input
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest send(final InputStream input) throws HttpRequestException {
+ try {
+ openOutput();
+ copy(input, output);
+ } catch (IOException e) {
+ throw new HttpRequestException(e);
+ }
+ return this;
+ }
+
+ /**
+ * Write reader to request body
+ *
+ * The given reader will be closed once sending completes
+ *
+ * @param input
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest send(final Reader input) throws HttpRequestException {
+ try {
+ openOutput();
+ } catch (IOException e) {
+ throw new HttpRequestException(e);
+ }
+ final Writer writer = new OutputStreamWriter(output,
+ output.encoder.charset());
+ return new FlushOperation
+ * The charset configured via {@link #contentType(String)} will be used and
+ * UTF-8 will be used if it is unset.
+ *
+ * @param value
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest send(final CharSequence value) throws HttpRequestException {
+ try {
+ openOutput();
+ output.write(value.toString());
+ } catch (IOException e) {
+ throw new HttpRequestException(e);
+ }
+ return this;
+ }
+
+ /**
+ * Create writer to request output stream
+ *
+ * @return writer
+ * @throws HttpRequestException
+ */
+ public OutputStreamWriter writer() throws HttpRequestException {
+ try {
+ openOutput();
+ return new OutputStreamWriter(output, output.encoder.charset());
+ } catch (IOException e) {
+ throw new HttpRequestException(e);
+ }
+ }
+
+ /**
+ * Write the values in the map as form data to the request body
+ *
+ * The pairs specified will be URL-encoded in UTF-8 and sent with the
+ * 'application/x-www-form-urlencoded' content-type
+ *
+ * @param values
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest form(final Map, ?> values) throws HttpRequestException {
+ return form(values, CHARSET_UTF8);
+ }
+
+ /**
+ * Write the key and value in the entry as form data to the request body
+ *
+ * The pair specified will be URL-encoded in UTF-8 and sent with the
+ * 'application/x-www-form-urlencoded' content-type
+ *
+ * @param entry
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest form(final Entry, ?> entry) throws HttpRequestException {
+ return form(entry, CHARSET_UTF8);
+ }
+
+ /**
+ * Write the key and value in the entry as form data to the request body
+ *
+ * The pair specified will be URL-encoded and sent with the
+ * 'application/x-www-form-urlencoded' content-type
+ *
+ * @param entry
+ * @param charset
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest form(final Entry, ?> entry, final String charset)
+ throws HttpRequestException {
+ return form(entry.getKey(), entry.getValue(), charset);
+ }
+
+ /**
+ * Write the name/value pair as form data to the request body
+ *
+ * The pair specified will be URL-encoded in UTF-8 and sent with the
+ * 'application/x-www-form-urlencoded' content-type
+ *
+ * @param name
+ * @param value
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest form(final Object name, final Object value)
+ throws HttpRequestException {
+ return form(name, value, CHARSET_UTF8);
+ }
+
+ /**
+ * Write the name/value pair as form data to the request body
+ *
+ * The values specified will be URL-encoded and sent with the
+ * 'application/x-www-form-urlencoded' content-type
+ *
+ * @param name
+ * @param value
+ * @param charset
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest form(final Object name, final Object value, String charset)
+ throws HttpRequestException {
+ final boolean first = !form;
+ if (first) {
+ contentType(CONTENT_TYPE_FORM, charset);
+ form = true;
+ }
+ String validCharset = getValidCharset(charset);
+ try {
+ openOutput();
+ if (!first)
+ output.write('&');
+ output.write(URLEncoder.encode(name.toString(), validCharset));
+ output.write('=');
+ if (value != null)
+ output.write(URLEncoder.encode(value.toString(), validCharset));
+ } catch (IOException e) {
+ throw new HttpRequestException(e);
+ }
+ return this;
+ }
+
+ /**
+ * Write the values in the map as encoded form data to the request body
+ *
+ * @param values
+ * @param charset
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest form(final Map, ?> values, final String charset)
+ throws HttpRequestException {
+ if (!values.isEmpty())
+ for (Entry, ?> entry : values.entrySet())
+ form(entry, charset);
+ return this;
+ }
+
+ /**
+ * Configure HTTPS connection to trust all certificates
+ *
+ * This method does nothing if the current request is not a HTTPS request
+ *
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest trustAllCerts() throws HttpRequestException {
+ final HttpURLConnection connection = getConnection();
+ if (connection instanceof HttpsURLConnection)
+ ((HttpsURLConnection) connection)
+ .setSSLSocketFactory(getTrustedFactory());
+ return this;
+ }
+
+ /**
+ * Configure HTTPS connection to trust all hosts using a custom
+ * {@link HostnameVerifier} that always returns
+ * This method does nothing if the current request is not a HTTPS request
+ *
+ * @return this request
+ */
+ public HttpRequest trustAllHosts() {
+ final HttpURLConnection connection = getConnection();
+ if (connection instanceof HttpsURLConnection)
+ ((HttpsURLConnection) connection)
+ .setHostnameVerifier(getTrustedVerifier());
+ return this;
+ }
+
+ /**
+ * Get the {@link URL} of this request's connection
+ *
+ * @return request URL
+ */
+ public URL url() {
+ return getConnection().getURL();
+ }
+
+ /**
+ * Get the HTTP method of this request
+ *
+ * @return method
+ */
+ public String method() {
+ return getConnection().getRequestMethod();
+ }
+
+ /**
+ * Configure an HTTP proxy on this connection. Use {{@link #proxyBasic(String, String)} if
+ * this proxy requires basic authentication.
+ *
+ * @param proxyHost
+ * @param proxyPort
+ * @return this request
+ */
+ public HttpRequest useProxy(final String proxyHost, final int proxyPort) {
+ if (connection != null)
+ throw new IllegalStateException("The connection has already been created. This method must be called before reading or writing to the request.");
+
+ this.httpProxyHost = proxyHost;
+ this.httpProxyPort = proxyPort;
+ return this;
+ }
+
+ /**
+ * Set whether or not the underlying connection should follow redirects in
+ * the response.
+ *
+ * @param followRedirects - true fo follow redirects, false to not.
+ * @return this request
+ */
+ public HttpRequest followRedirects(final boolean followRedirects) {
+ getConnection().setInstanceFollowRedirects(followRedirects);
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/com.eclipsesource.tabris.tracking/src/com/eclipsesource/tabris/tracking/internal/analytics/request/RequestAssembler.java b/com.eclipsesource.tabris.tracking/src/com/eclipsesource/tabris/tracking/internal/analytics/request/RequestAssembler.java
new file mode 100644
index 0000000..5ad7590
--- /dev/null
+++ b/com.eclipsesource.tabris.tracking/src/com/eclipsesource/tabris/tracking/internal/analytics/request/RequestAssembler.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2014 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * EclipseSource - initial API and implementation
+ ******************************************************************************/
+package com.eclipsesource.tabris.tracking.internal.analytics.request;
+
+import static com.eclipsesource.tabris.internal.Clauses.when;
+import static com.eclipsesource.tabris.internal.Clauses.whenNull;
+import static com.eclipsesource.tabris.tracking.internal.analytics.request.RequestKeyProvider.getRequestKey;
+import static com.eclipsesource.tabris.tracking.internal.analytics.request.RequestKeys.APP_NAME;
+import static com.eclipsesource.tabris.tracking.internal.analytics.request.RequestKeys.CLIENT_ID;
+import static com.eclipsesource.tabris.tracking.internal.analytics.request.RequestValueProvider.getRequestValue;
+import static com.eclipsesource.tabris.tracking.internal.analytics.request.RequestValues.HIT_APPVIEW;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.eclipsesource.tabris.tracking.internal.analytics.model.Requestable;
+
+
+@SuppressWarnings("restriction")
+public class RequestAssembler {
+
+ private final String appName;
+ private final Listtrue
+ *
+ * @param ignore
+ * @return this request
+ */
+ public HttpRequest ignoreCloseExceptions(final boolean ignore) {
+ ignoreCloseExceptions = ignore;
+ return this;
+ }
+
+ /**
+ * Get whether or not exceptions thrown by {@link Closeable#close()} are
+ * ignored
+ *
+ * @return true if ignoring, false if throwing
+ */
+ public boolean ignoreCloseExceptions() {
+ return ignoreCloseExceptions;
+ }
+
+ /**
+ * Get the status code of the response
+ *
+ * @return the response code
+ * @throws HttpRequestException
+ */
+ public int code() throws HttpRequestException {
+ try {
+ closeOutput();
+ return getConnection().getResponseCode();
+ } catch (IOException e) {
+ throw new HttpRequestException(e);
+ }
+ }
+
+ /**
+ * Set the value of the given {@link AtomicInteger} to the status code of the
+ * response
+ *
+ * @param output
+ * @return this request
+ * @throws HttpRequestException
+ */
+ public HttpRequest code(final AtomicInteger output)
+ throws HttpRequestException {
+ output.set(code());
+ return this;
+ }
+
+ /**
+ * Is the response code a 200 OK?
+ *
+ * @return true if 200, false otherwise
+ * @throws HttpRequestException
+ */
+ public boolean ok() throws HttpRequestException {
+ return HTTP_OK == code();
+ }
+
+ /**
+ * Is the response code a 201 Created?
+ *
+ * @return true if 201, false otherwise
+ * @throws HttpRequestException
+ */
+ public boolean created() throws HttpRequestException {
+ return HTTP_CREATED == code();
+ }
+
+ /**
+ * Is the response code a 204 No Content?
+ *
+ * @return true if 204, false otherwise
+ * @throws HttpRequestException
+ */
+ public boolean noContent() throws HttpRequestException {
+ return HTTP_NO_CONTENT == code();
+ }
+
+ /**
+ * Is the response code a 500 Internal Server Error?
+ *
+ * @return true if 500, false otherwise
+ * @throws HttpRequestException
+ */
+ public boolean serverError() throws HttpRequestException {
+ return HTTP_INTERNAL_ERROR == code();
+ }
+
+ /**
+ * Is the response code a 400 Bad Request?
+ *
+ * @return true if 400, false otherwise
+ * @throws HttpRequestException
+ */
+ public boolean badRequest() throws HttpRequestException {
+ return HTTP_BAD_REQUEST == code();
+ }
+
+ /**
+ * Is the response code a 404 Not Found?
+ *
+ * @return true if 404, false otherwise
+ * @throws HttpRequestException
+ */
+ public boolean notFound() throws HttpRequestException {
+ return HTTP_NOT_FOUND == code();
+ }
+
+ /**
+ * Is the response code a 304 Not Modified?
+ *
+ * @return true if 304, false otherwise
+ * @throws HttpRequestException
+ */
+ public boolean notModified() throws HttpRequestException {
+ return HTTP_NOT_MODIFIED == code();
+ }
+
+ /**
+ * Get status message of the response
+ *
+ * @return message
+ * @throws HttpRequestException
+ */
+ public String message() throws HttpRequestException {
+ try {
+ closeOutput();
+ return getConnection().getResponseMessage();
+ } catch (IOException e) {
+ throw new HttpRequestException(e);
+ }
+ }
+
+ /**
+ * Disconnect the connection
+ *
+ * @return this request
+ */
+ public HttpRequest disconnect() {
+ getConnection().disconnect();
+ return this;
+ }
+
+ /**
+ * Set chunked streaming mode to the given size
+ *
+ * @param size
+ * @return this request
+ */
+ public HttpRequest chunk(final int size) {
+ getConnection().setChunkedStreamingMode(size);
+ return this;
+ }
+
+ /**
+ * Set the size used when buffering and copying between streams
+ * true
for each
+ * host verified
+ *