验证中...
码云 Gitee IDE 全新上线——支持 Git 管理的轻量在线编码环境
语言: Java
分类: 其他
最后更新于 2018-06-14 11:29
gistfile1.txt
原始数据 复制代码
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259
/*
* Copyright (c) 2014 Kevin Sawicki <kevinsawicki@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
package com.github.kevinsawicki.http;
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
import static java.net.HttpURLConnection.HTTP_CREATED;
import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
import static java.net.HttpURLConnection.HTTP_NOT_MODIFIED;
import static java.net.HttpURLConnection.HTTP_OK;
import static java.net.Proxy.Type.HTTP;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.Flushable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.security.AccessController;
import java.security.GeneralSecurityException;
import java.security.PrivilegedAction;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.GZIPInputStream;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* A fluid interface for making HTTP requests using an underlying
* {@link HttpURLConnection} (or sub-class).
* <p>
* 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;
else
return CHARSET_UTF8;
}
private static SSLSocketFactory getTrustedFactory()
throws HttpRequestException {
if (TRUSTED_FACTORY == null) {
final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] chain, String authType) {
// Intentionally left blank
}
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() {
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;
}
private static StringBuilder addParam(final Object key, Object value,
final StringBuilder result) {
if (value != null && value.getClass().isArray())
value = arrayToList(value);
if (value instanceof Iterable<?>) {
Iterator<?> iterator = ((Iterable<?>) value).iterator();
while (iterator.hasNext()) {
result.append(key);
result.append("[]=");
Object element = iterator.next();
if (element != null)
result.append(element);
if (iterator.hasNext())
result.append("&");
}
} else {
result.append(key);
result.append("=");
if (value != null)
result.append(value);
}
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() {
public HttpURLConnection create(URL url) throws IOException {
return (HttpURLConnection) url.openConnection();
}
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() {
public void onUpload(long uploaded, long total) {
}
};
}
/**
* <p>
* Encodes and decodes to and from Base64 notation.
* </p>
* <p>
* 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 <a
* href="http://iharder.net/base64">http://iharder.net/base64</a> periodically
* to check for updates or to contribute improvements.
* </p>
*
* @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() {
}
/**
* <p>
* Encodes up to three bytes of the array <var>source</var> and writes the
* resulting four Base64 bytes to <var>destination</var>. The source and
* destination arrays can be manipulated anywhere along their length by
* specifying <var>srcOffset</var> and <var>destOffset</var>. This method
* does not check to make sure your arrays are large enough to accomodate
* <var>srcOffset</var> + 3 for the <var>source</var> array or
* <var>destOffset</var> + 4 for the <var>destination</var> array. The
* actual number of significant bytes in your array is given by
* <var>numSigBytes</var>.
* </p>
* <p>
* This is the lowest level of the encoding methods with all possible
* parameters.
* </p>
*
* @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 <var>destination</var> 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",
off, len, 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;
} else
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 <V>
*/
protected static abstract class Operation<V> implements Callable<V> {
/**
* Run operation
*
* @return result
* @throws HttpRequestException
* @throws IOException
*/
protected abstract V run() throws HttpRequestException, IOException;
/**
* Operation complete callback
*
* @throws IOException
*/
protected abstract void done() throws IOException;
public V call() throws HttpRequestException {
boolean thrown = false;
try {
return run();
} catch (HttpRequestException e) {
thrown = true;
throw e;
} catch (IOException e) {
thrown = true;
throw new HttpRequestException(e);
} finally {
try {
done();
} catch (IOException e) {
if (!thrown)
throw new HttpRequestException(e);
}
}
}
}
/**
* Class that ensures a {@link Closeable} gets closed with proper exception
* handling.
*
* @param <V>
*/
protected static abstract class CloseOperation<V> extends Operation<V> {
private final Closeable closeable;
private final boolean ignoreCloseExceptions;
/**
* Create closer for operation
*
* @param closeable
* @param ignoreCloseExceptions
*/
protected CloseOperation(final Closeable closeable,
final boolean ignoreCloseExceptions) {
this.closeable = closeable;
this.ignoreCloseExceptions = ignoreCloseExceptions;
}
@Override
protected void done() throws IOException {
if (closeable instanceof Flushable)
((Flushable) closeable).flush();
if (ignoreCloseExceptions)
try {
closeable.close();
} catch (IOException e) {
// Ignored
}
else
closeable.close();
}
}
/**
* Class that and ensures a {@link Flushable} gets flushed with proper
* exception handling.
*
* @param <V>
*/
protected static abstract class FlushOperation<V> extends Operation<V> {
private final Flushable flushable;
/**
* Create flush operation
*
* @param flushable
*/
protected FlushOperation(final Flushable flushable) {
this.flushable = flushable;
}
@Override
protected void done() throws IOException {
flushable.flush();
}
}
/**
* Request output stream
*/
public static class RequestOutputStream extends BufferedOutputStream {
private final CharsetEncoder encoder;
/**
* Create request output stream
*
* @param stream
* @param charset
* @param bufferSize
*/
public RequestOutputStream(final OutputStream stream, final String charset,
final int bufferSize) {
super(stream, bufferSize);
encoder = Charset.forName(getValidCharset(charset)).newEncoder();
}
/**
* Write string to stream
*
* @param value
* @return this stream
* @throws IOException
*/
public RequestOutputStream write(final String value) throws IOException {
final ByteBuffer bytes = encoder.encode(CharBuffer.wrap(value));
super.write(bytes.array(), 0, bytes.limit());
return this;
}
}
/**
* Represents array of any type as list of objects so we can easily iterate over it
* @param array of elements
* @return list with the same elements
*/
private static List<Object> arrayToList(final Object array) {
if (array instanceof Object[])
return Arrays.asList((Object[]) array);
List<Object> result = new ArrayList<Object>();
// Arrays of the primitive types can't be cast to array of Object, so this:
if (array instanceof int[])
for (int value : (int[]) array) result.add(value);
else if (array instanceof boolean[])
for (boolean value : (boolean[]) array) result.add(value);
else if (array instanceof long[])
for (long value : (long[]) array) result.add(value);
else if (array instanceof float[])
for (float value : (float[]) array) result.add(value);
else if (array instanceof double[])
for (double value : (double[]) array) result.add(value);
else if (array instanceof short[])
for (short value : (short[]) array) result.add(value);
else if (array instanceof byte[])
for (byte value : (byte[]) array) result.add(value);
else if (array instanceof char[])
for (char value : (char[]) array) result.add(value);
return result;
}
/**
* Encode the given URL as an ASCII {@link String}
* <p>
* 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
* <p>
* 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;
Iterator<?> iterator = params.entrySet().iterator();
entry = (Entry<?, ?>) iterator.next();
addParam(entry.getKey().toString(), entry.getValue(), result);
while (iterator.hasNext()) {
result.append('&');
entry = (Entry<?, ?>) iterator.next();
addParam(entry.getKey().toString(), entry.getValue(), result);
}
return result.toString();
}
/**
* Append given name/value pairs as query parameters to the base URL
* <p>
* 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);
addParam(params[0], params[1], result);
for (int i = 2; i < params.length; i += 2) {
result.append('&');
addParam(params[i], params[i + 1], result);
}
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, Object...)
* @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, Object...)
* @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, Object...)
* @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, Object...)
* @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, Object...)
* @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.
* <p>
* 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.
* <p>
* 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' and 'https.proxyHost' properties to the given host
* value.
* <p>
* 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' and 'https.proxyPort' properties to the given port
* number.
* <p>
* 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.
* <p>
* Hosts will be separated by a '|' character.
* <p>
* 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.
* <p>
* 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<String> action;
if (value != null)
action = new PrivilegedAction<String>() {
public String run() {
return System.setProperty(name, value);
}
};
else
action = new PrivilegedAction<String>() {
public String run() {
return System.clearProperty(name);
}
};
return AccessController.doPrivileged(action);
}
private HttpURLConnection connection = null;
private final URL url;
private final String requestMethod;
private RequestOutputStream output;
private boolean multipart;
private boolean form;
private boolean ignoreCloseExceptions = true;
private boolean uncompress = false;
private int bufferSize = 8192;
private long totalSize = -1;
private long totalWritten = 0;
private String httpProxyHost;
private int httpProxyPort;
private UploadProgress progress = UploadProgress.DEFAULT;
/**
* Create HTTP connection wrapper
*
* @param url Remote resource URL.
* @param method HTTP request method (e.g., "GET", "POST").
* @throws HttpRequestException
*/
public HttpRequest(final CharSequence url, final String method)
throws HttpRequestException {
try {
this.url = new URL(url.toString());
} catch (MalformedURLException e) {
throw new HttpRequestException(e);
}
this.requestMethod = method;
}
/**
* Create HTTP connection wrapper
*
* @param url Remote resource URL.
* @param method HTTP request method (e.g., "GET", "POST").
* @throws HttpRequestException
*/
public HttpRequest(final URL url, final String method)
throws HttpRequestException {
this.url = url;
this.requestMethod = method;
}
private Proxy createProxy() {
return new Proxy(HTTP, new InetSocketAddress(httpProxyHost, httpProxyPort));
}
private HttpURLConnection createConnection() {
try {
final HttpURLConnection connection;
if (httpProxyHost != null)
connection = CONNECTION_FACTORY.create(url, createProxy());
else
connection = CONNECTION_FACTORY.create(url);
connection.setRequestMethod(requestMethod);
return connection;
} catch (IOException e) {
throw new HttpRequestException(e);
}
}
@Override
public String toString() {
return method() + ' ' + url();
}
/**
* Get underlying connection
*
* @return connection
*/
public HttpURLConnection getConnection() {
if (connection == null)
connection = createConnection();
return connection;
}
/**
* Set whether or not to ignore exceptions that occur from calling
* {@link Closeable#close()}
* <p>
* The default value of this setting is <code>true</code>
*
* @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
* <p>
* This size is also used for send and receive buffers created for both char
* and byte arrays
* <p>
* 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
* <p>
* 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.
* <p>
* This will only affect requests that have the 'Content-Encoding' response
* header set to 'gzip'.
* <p>
* This causes all receive methods to use a {@link GZIPInputStream} when
* applicable so that higher level streams and readers can read the data
* uncompressed.
* <p>
* 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);
else
return new ByteArrayOutputStream();
}
/**
* Get response as {@link String} in given character set
* <p>
* 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<String> output) throws HttpRequestException {
output.set(body());
return this;
}
/**
* Get the response body as a {@link String} and set it as the value of the
* given reference.
*
* @param output
* @param charset
* @return this request
* @throws HttpRequestException
*/
public HttpRequest body(final AtomicReference<String> output, final String charset) throws HttpRequestException {
output.set(body(charset));
return this;
}
/**
* Is the response body empty?
*
* @return true if the Content-Length response header is 0, false otherwise
* @throws HttpRequestException
*/
public boolean isBodyEmpty() throws HttpRequestException {
return contentLength() == 0;
}
/**
* Get response as byte array
*
* @return byte array
* @throws HttpRequestException
*/
public byte[] bytes() throws HttpRequestException {
final ByteArrayOutputStream output = byteStream();
try {
copy(buffer(), output);
} catch (IOException e) {
throw new HttpRequestException(e);
}
return output.toByteArray();
}
/**
* Get response in a buffered stream
*
* @see #bufferSize(int)
* @return stream
* @throws HttpRequestException
*/
public BufferedInputStream buffer() throws HttpRequestException {
return new BufferedInputStream(stream(), bufferSize);
}
/**
* Get stream to response body
*
* @return stream
* @throws HttpRequestException
*/
public InputStream stream() throws HttpRequestException {
InputStream stream;
if (code() < HTTP_BAD_REQUEST)
try {
stream = getConnection().getInputStream();
} catch (IOException e) {
throw new HttpRequestException(e);
}
else {
stream = getConnection().getErrorStream();
if (stream == null)
try {
stream = getConnection().getInputStream();
} catch (IOException e) {
if (contentLength() > 0)
throw new HttpRequestException(e);
else
stream = new ByteArrayInputStream(new byte[0]);
}
}
if (!uncompress || !ENCODING_GZIP.equals(contentEncoding()))
return stream;
else
try {
return new GZIPInputStream(stream);
} catch (IOException e) {
throw new HttpRequestException(e);
}
}
/**
* Get reader to response body using given character set.
* <p>
* 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<HttpRequest>(output, ignoreCloseExceptions) {
@Override
protected HttpRequest run() throws HttpRequestException, IOException {
return receive(output);
}
}.call();
}
/**
* Stream response to given output stream
*
* @param output
* @return this request
* @throws HttpRequestException
*/
public HttpRequest receive(final OutputStream output)
throws HttpRequestException {
try {
return copy(buffer(), output);
} catch (IOException e) {
throw new HttpRequestException(e);
}
}
/**
* Stream response to given print stream
*
* @param output
* @return this request
* @throws HttpRequestException
*/
public HttpRequest receive(final PrintStream output)
throws HttpRequestException {
return receive((OutputStream) output);
}
/**
* Receive response into the given appendable
*
* @param appendable
* @return this request
* @throws HttpRequestException
*/
public HttpRequest receive(final Appendable appendable)
throws HttpRequestException {
final BufferedReader reader = bufferedReader();
return new CloseOperation<HttpRequest>(reader, ignoreCloseExceptions) {
@Override
public HttpRequest run() throws IOException {
final CharBuffer buffer = CharBuffer.allocate(bufferSize);
int read;
while ((read = reader.read(buffer)) != -1) {
buffer.rewind();
appendable.append(buffer, 0, read);
buffer.rewind();
}
return HttpRequest.this;
}
}.call();
}
/**
* Receive response into the given writer
*
* @param writer
* @return this request
* @throws HttpRequestException
*/
public HttpRequest receive(final Writer writer) throws HttpRequestException {
final BufferedReader reader = bufferedReader();
return new CloseOperation<HttpRequest>(reader, ignoreCloseExceptions) {
@Override
public HttpRequest run() throws IOException {
return copy(reader, writer);
}
}.call();
}
/**
* Set read timeout on connection to given value
*
* @param timeout
* @return this request
*/
public HttpRequest readTimeout(final int timeout) {
getConnection().setReadTimeout(timeout);
return this;
}
/**
* Set connect timeout on connection to given value
*
* @param timeout
* @return this request
*/
public HttpRequest connectTimeout(final int timeout) {
getConnection().setConnectTimeout(timeout);
return this;
}
/**
* Set header name to given value
*
* @param name
* @param value
* @return this request
*/
public HttpRequest header(final String name, final String value) {
getConnection().setRequestProperty(name, value);
return this;
}
/**
* Set header name to given value
*
* @param name
* @param value
* @return this request
*/
public HttpRequest header(final String name, final Number value) {
return header(name, value != null ? value.toString() : null);
}
/**
* Set all headers found in given map where the keys are the header names and
* the values are the header values
*
* @param headers
* @return this request
*/
public HttpRequest headers(final Map<String, String> headers) {
if (!headers.isEmpty())
for (Entry<String, String> header : headers.entrySet())
header(header);
return this;
}
/**
* Set header to have given entry's key as the name and value as the value
*
* @param header
* @return this request
*/
public HttpRequest header(final Entry<String, String> header) {
return header(header.getKey(), header.getValue());
}
/**
* Get a response header
*
* @param name
* @return response header
* @throws HttpRequestException
*/
public String header(final String name) throws HttpRequestException {
closeOutputQuietly();
return getConnection().getHeaderField(name);
}
/**
* Get all the response headers
*
* @return map of response header names to their value(s)
* @throws HttpRequestException
*/
public Map<String, List<String>> headers() throws HttpRequestException {
closeOutputQuietly();
return getConnection().getHeaderFields();
}
/**
* Get a date header from the response falling back to returning -1 if the
* header is missing or parsing fails
*
* @param name
* @return date, -1 on failures
* @throws HttpRequestException
*/
public long dateHeader(final String name) throws HttpRequestException {
return dateHeader(name, -1L);
}
/**
* Get a date header from the response falling back to returning the given
* default value if the header is missing or parsing fails
*
* @param name
* @param defaultValue
* @return date, default value on failures
* @throws HttpRequestException
*/
public long dateHeader(final String name, final long defaultValue)
throws HttpRequestException {
closeOutputQuietly();
return getConnection().getHeaderFieldDate(name, defaultValue);
}
/**
* Get an integer header from the response falling back to returning -1 if the
* header is missing or parsing fails
*
* @param name
* @return header value as an integer, -1 when missing or parsing fails
* @throws HttpRequestException
*/
public int intHeader(final String name) throws HttpRequestException {
return intHeader(name, -1);
}
/**
* Get an integer header value from the response falling back to the given
* default value if the header is missing or if parsing fails
*
* @param name
* @param defaultValue
* @return header value as an integer, default value when missing or parsing
* fails
* @throws HttpRequestException
*/
public int intHeader(final String name, final int defaultValue)
throws HttpRequestException {
closeOutputQuietly();
return getConnection().getHeaderFieldInt(name, defaultValue);
}
/**
* Get all values of the given header from the response
*
* @param name
* @return non-null but possibly empty array of {@link String} header values
*/
public String[] headers(final String name) {
final Map<String, List<String>> headers = headers();
if (headers == null || headers.isEmpty())
return EMPTY_STRINGS;
final List<String> values = headers.get(name);
if (values != null && !values.isEmpty())
return values.toArray(new String[values.size()]);
else
return EMPTY_STRINGS;
}
/**
* Get parameter with given name from header value in response
*
* @param headerName
* @param paramName
* @return parameter value or null if missing
*/
public String parameter(final String headerName, final String paramName) {
return getParam(header(headerName), paramName);
}
/**
* Get all parameters from header value in response
* <p>
* 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<String, String> parameters(final String headerName) {
return getParams(header(headerName));
}
/**
* Get parameter values from header value
*
* @param header
* @return parameter value or null if none
*/
protected Map<String, String> getParams(final String header) {
if (header == null || header.length() == 0)
return Collections.emptyMap();
final int headerLength = header.length();
int start = header.indexOf(';') + 1;
if (start == 0 || start == headerLength)
return Collections.emptyMap();
int end = header.indexOf(';', start);
if (end == -1)
end = headerLength;
Map<String, String> params = new LinkedHashMap<String, String>();
while (start < end) {
int nameEnd = header.indexOf('=', start);
if (nameEnd != -1 && nameEnd < end) {
String name = header.substring(start, nameEnd).trim();
if (name.length() > 0) {
String value = header.substring(nameEnd + 1, end).trim();
int length = value.length();
if (length != 0)
if (length > 2 && '"' == value.charAt(0)
&& '"' == value.charAt(length - 1))
params.put(name, value.substring(1, length - 1));
else
params.put(name, value);
}
}
start = end + 1;
end = header.indexOf(';', start);
if (end == -1)
end = headerLength;
}
return params;
}
/**
* Get parameter value from header value
*
* @param value
* @param paramName
* @return parameter value or null if none
*/
protected String getParam(final String value, final String paramName) {
if (value == null || value.length() == 0)
return null;
final int length = value.length();
int start = value.indexOf(';') + 1;
if (start == 0 || start == length)
return null;
int end = value.indexOf(';', start);
if (end == -1)
end = length;
while (start < end) {
int nameEnd = value.indexOf('=', start);
if (nameEnd != -1 && nameEnd < end
&& paramName.equals(value.substring(start, nameEnd).trim())) {
String paramValue = value.substring(nameEnd + 1, end).trim();
int valueLength = paramValue.length();
if (valueLength != 0)
if (valueLength > 2 && '"' == paramValue.charAt(0)
&& '"' == paramValue.charAt(valueLength - 1))
return paramValue.substring(1, valueLength - 1);
else
return paramValue;
}
start = end + 1;
end = value.indexOf(';', start);
if (end == -1)
end = length;
}
return null;
}
/**
* Get 'charset' parameter from 'Content-Type' response header
*
* @return charset or null if none
*/
public String charset() {
return parameter(HEADER_CONTENT_TYPE, PARAM_CHARSET);
}
/**
* Set the 'User-Agent' header to given value
*
* @param userAgent
* @return this request
*/
public HttpRequest userAgent(final String userAgent) {
return header(HEADER_USER_AGENT, userAgent);
}
/**
* Set the 'Referer' header to given value
*
* @param referer
* @return this request
*/
public HttpRequest referer(final String referer) {
return header(HEADER_REFERER, referer);
}
/**
* Set value of {@link HttpURLConnection#setUseCaches(boolean)}
*
* @param useCaches
* @return this request
*/
public HttpRequest useCaches(final boolean useCaches) {
getConnection().setUseCaches(useCaches);
return this;
}
/**
* Set the 'Accept-Encoding' header to given value
*
* @param acceptEncoding
* @return this request
*/
public HttpRequest acceptEncoding(final String acceptEncoding) {
return header(HEADER_ACCEPT_ENCODING, acceptEncoding);
}
/**
* Set the 'Accept-Encoding' header to 'gzip'
*
* @see #uncompress(boolean)
* @return this request
*/
public HttpRequest acceptGzipEncoding() {
return acceptEncoding(ENCODING_GZIP);
}
/**
* Set the 'Accept-Charset' header to given value
*
* @param acceptCharset
* @return this request
*/
public HttpRequest acceptCharset(final String acceptCharset) {
return header(HEADER_ACCEPT_CHARSET, acceptCharset);
}
/**
* Get the 'Content-Encoding' header from the response
*
* @return this request
*/
public String contentEncoding() {
return header(HEADER_CONTENT_ENCODING);
}
/**
* Get the 'Server' header from the response
*
* @return server
*/
public String server() {
return header(HEADER_SERVER);
}
/**
* Get the 'Date' header from the response
*
* @return date value, -1 on failures
*/
public long date() {
return dateHeader(HEADER_DATE);
}
/**
* Get the 'Cache-Control' header from the response
*
* @return cache control
*/
public String cacheControl() {
return header(HEADER_CACHE_CONTROL);
}
/**
* Get the 'ETag' header from the response
*
* @return entity tag
*/
public String eTag() {
return header(HEADER_ETAG);
}
/**
* Get the 'Expires' header from the response
*
* @return expires value, -1 on failures
*/
public long expires() {
return dateHeader(HEADER_EXPIRES);
}
/**
* Get the 'Last-Modified' header from the response
*
* @return last modified value, -1 on failures
*/
public long lastModified() {
return dateHeader(HEADER_LAST_MODIFIED);
}
/**
* Get the 'Location' header from the response
*
* @return location
*/
public String location() {
return header(HEADER_LOCATION);
}
/**
* Set the 'Authorization' header to given value
*
* @param authorization
* @return this request
*/
public HttpRequest authorization(final String authorization) {
return header(HEADER_AUTHORIZATION, authorization);
}
/**
* Set the 'Proxy-Authorization' header to given value
*
* @param proxyAuthorization
* @return this request
*/
public HttpRequest proxyAuthorization(final String proxyAuthorization) {
return header(HEADER_PROXY_AUTHORIZATION, proxyAuthorization);
}
/**
* Set the 'Authorization' header to given values in Basic authentication
* format
*
* @param name
* @param password
* @return this request
*/
public HttpRequest basic(final String name, final String password) {
return authorization("Basic " + Base64.encode(name + ':' + password));
}
/**
* Set the 'Proxy-Authorization' header to given values in Basic authentication
* format
*
* @param name
* @param password
* @return this request
*/
public HttpRequest proxyBasic(final String name, final String password) {
return proxyAuthorization("Basic " + Base64.encode(name + ':' + password));
}
/**
* Set the 'If-Modified-Since' request header to the given value
*
* @param ifModifiedSince
* @return this request
*/
public HttpRequest ifModifiedSince(final long ifModifiedSince) {
getConnection().setIfModifiedSince(ifModifiedSince);
return this;
}
/**
* Set the 'If-None-Match' request header to the given value
*
* @param ifNoneMatch
* @return this request
*/
public HttpRequest ifNoneMatch(final String ifNoneMatch) {
return header(HEADER_IF_NONE_MATCH, ifNoneMatch);
}
/**
* Set the 'Content-Type' request header to the given value
*
* @param contentType
* @return this request
*/
public HttpRequest contentType(final String contentType) {
return contentType(contentType, null);
}
/**
* Set the 'Content-Type' request header to the given value and charset
*
* @param contentType
* @param charset
* @return this request
*/
public HttpRequest contentType(final String contentType, final String charset) {
if (charset != null && charset.length() > 0) {
final String separator = "; " + PARAM_CHARSET + '=';
return header(HEADER_CONTENT_TYPE, contentType + separator + charset);
} else
return header(HEADER_CONTENT_TYPE, contentType);
}
/**
* Get the 'Content-Type' header from the response
*
* @return response header value
*/
public String contentType() {
return header(HEADER_CONTENT_TYPE);
}
/**
* Get the 'Content-Length' header from the response
*
* @return response header value
*/
public int contentLength() {
return intHeader(HEADER_CONTENT_LENGTH);
}
/**
* Set the 'Content-Length' request header to the given value
*
* @param contentLength
* @return this request
*/
public HttpRequest contentLength(final String contentLength) {
return contentLength(Integer.parseInt(contentLength));
}
/**
* Set the 'Content-Length' request header to the given value
*
* @param contentLength
* @return this request
*/
public HttpRequest contentLength(final int contentLength) {
getConnection().setFixedLengthStreamingMode(contentLength);
return this;
}
/**
* Set the 'Accept' header to given value
*
* @param accept
* @return this request
*/
public HttpRequest accept(final String accept) {
return header(HEADER_ACCEPT, accept);
}
/**
* Set the 'Accept' header to 'application/json'
*
* @return this request
*/
public HttpRequest acceptJson() {
return accept(CONTENT_TYPE_JSON);
}
/**
* Copy from input stream to output stream
*
* @param input
* @param output
* @return this request
* @throws IOException
*/
protected HttpRequest copy(final InputStream input, final OutputStream output)
throws IOException {
return new CloseOperation<HttpRequest>(input, ignoreCloseExceptions) {
@Override
public HttpRequest run() throws IOException {
final byte[] buffer = new byte[bufferSize];
int read;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
totalWritten += read;
progress.onUpload(totalWritten, totalSize);
}
return HttpRequest.this;
}
}.call();
}
/**
* Copy from reader to writer
*
* @param input
* @param output
* @return this request
* @throws IOException
*/
protected HttpRequest copy(final Reader input, final Writer output)
throws IOException {
return new CloseOperation<HttpRequest>(input, ignoreCloseExceptions) {
@Override
public HttpRequest run() throws IOException {
final char[] buffer = new char[bufferSize];
int read;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
totalWritten += read;
progress.onUpload(totalWritten, -1);
}
return HttpRequest.this;
}
}.call();
}
/**
* Set the UploadProgress callback for this request
*
* @param callback
* @return this request
*/
public HttpRequest progress(final UploadProgress callback) {
if (callback == null)
progress = UploadProgress.DEFAULT;
else
progress = callback;
return this;
}
private HttpRequest incrementTotalSize(final long size) {
if (totalSize == -1)
totalSize = 0;
totalSize += size;
return this;
}
/**
* Close output stream
*
* @return this request
* @throws HttpRequestException
* @throws IOException
*/
protected HttpRequest closeOutput() throws IOException {
progress(null);
if (output == null)
return this;
if (multipart)
output.write(CRLF + "--" + BOUNDARY + "--" + CRLF);
if (ignoreCloseExceptions)
try {
output.close();
} catch (IOException ignored) {
// Ignored
}
else
output.close();
output = null;
return this;
}
/**
* Call {@link #closeOutput()} and re-throw a caught {@link IOException}s as
* an {@link HttpRequestException}
*
* @return this request
* @throws HttpRequestException
*/
protected HttpRequest closeOutputQuietly() throws HttpRequestException {
try {
return closeOutput();
} catch (IOException e) {
throw new HttpRequestException(e);
}
}
/**
* Open output stream
*
* @return this request
* @throws IOException
*/
protected HttpRequest openOutput() throws IOException {
if (output != null)
return this;
getConnection().setDoOutput(true);
final String charset = getParam(
getConnection().getRequestProperty(HEADER_CONTENT_TYPE), PARAM_CHARSET);
output = new RequestOutputStream(getConnection().getOutputStream(), charset,
bufferSize);
return this;
}
/**
* Start part of a multipart
*
* @return this request
* @throws IOException
*/
protected HttpRequest startPart() throws IOException {
if (!multipart) {
multipart = true;
contentType(CONTENT_TYPE_MULTIPART).openOutput();
output.write("--" + BOUNDARY + CRLF);
} else
output.write(CRLF + "--" + BOUNDARY + CRLF);
return this;
}
/**
* Write part header
*
* @param name
* @param filename
* @return this request
* @throws IOException
*/
protected HttpRequest writePartHeader(final String name, final String filename)
throws IOException {
return writePartHeader(name, filename, null);
}
/**
* Write part header
*
* @param name
* @param filename
* @param contentType
* @return this request
* @throws IOException
*/
protected HttpRequest writePartHeader(final String name,
final String filename, final String contentType) throws IOException {
final StringBuilder partBuffer = new StringBuilder();
partBuffer.append("form-data; name=\"").append(name);
if (filename != null)
partBuffer.append("\"; filename=\"").append(filename);
partBuffer.append('"');
partHeader("Content-Disposition", partBuffer.toString());
if (contentType != null)
partHeader(HEADER_CONTENT_TYPE, contentType);
return send(CRLF);
}
/**
* Write part of a multipart request to the request body
*
* @param name
* @param part
* @return this request
*/
public HttpRequest part(final String name, final String part) {
return part(name, null, part);
}
/**
* Write part of a multipart request to the request body
*
* @param name
* @param filename
* @param part
* @return this request
* @throws HttpRequestException
*/
public HttpRequest part(final String name, final String filename,
final String part) throws HttpRequestException {
return part(name, filename, null, part);
}
/**
* Write part of a multipart request to the request body
*
* @param name
* @param filename
* @param contentType
* value of the Content-Type part header
* @param part
* @return this request
* @throws HttpRequestException
*/
public HttpRequest part(final String name, final String filename,
final String contentType, final String part) throws HttpRequestException {
try {
startPart();
writePartHeader(name, filename, contentType);
output.write(part);
} catch (IOException e) {
throw new HttpRequestException(e);
}
return this;
}
/**
* Write part of a multipart request to the request body
*
* @param name
* @param part
* @return this request
* @throws HttpRequestException
*/
public HttpRequest part(final String name, final Number part)
throws HttpRequestException {
return part(name, null, part);
}
/**
* Write part of a multipart request to the request body
*
* @param name
* @param filename
* @param part
* @return this request
* @throws HttpRequestException
*/
public HttpRequest part(final String name, final String filename,
final Number part) throws HttpRequestException {
return part(name, filename, part != null ? part.toString() : null);
}
/**
* Write part of a multipart request to the request body
*
* @param name
* @param part
* @return this request
* @throws HttpRequestException
*/
public HttpRequest part(final String name, final File part)
throws HttpRequestException {
return part(name, null, part);
}
/**
* Write part of a multipart request to the request body
*
* @param name
* @param filename
* @param part
* @return this request
* @throws HttpRequestException
*/
public HttpRequest part(final String name, final String filename,
final File part) throws HttpRequestException {
return part(name, filename, null, part);
}
/**
* Write part of a multipart request to the request body
*
* @param name
* @param filename
* @param contentType
* value of the Content-Type part header
* @param part
* @return this request
* @throws HttpRequestException
*/
public HttpRequest part(final String name, final String filename,
final String contentType, final File part) throws HttpRequestException {
final InputStream stream;
try {
stream = new BufferedInputStream(new FileInputStream(part));
incrementTotalSize(part.length());
} catch (IOException e) {
throw new HttpRequestException(e);
}
return part(name, filename, contentType, stream);
}
/**
* Write part of a multipart request to the request body
*
* @param name
* @param part
* @return this request
* @throws HttpRequestException
*/
public HttpRequest part(final String name, final InputStream part)
throws HttpRequestException {
return part(name, null, null, part);
}
/**
* Write part of a multipart request to the request body
*
* @param name
* @param filename
* @param contentType
* value of the Content-Type part header
* @param part
* @return this request
* @throws HttpRequestException
*/
public HttpRequest part(final String name, final String filename,
final String contentType, final InputStream part)
throws HttpRequestException {
try {
startPart();
writePartHeader(name, filename, contentType);
copy(part, output);
} catch (IOException e) {
throw new HttpRequestException(e);
}
return this;
}
/**
* Write a multipart header to the response body
*
* @param name
* @param value
* @return this request
* @throws HttpRequestException
*/
public HttpRequest partHeader(final String name, final String value)
throws HttpRequestException {
return send(name).send(": ").send(value).send(CRLF);
}
/**
* Write contents of file to request body
*
* @param input
* @return this request
* @throws HttpRequestException
*/
public HttpRequest send(final File input) throws HttpRequestException {
final InputStream stream;
try {
stream = new BufferedInputStream(new FileInputStream(input));
incrementTotalSize(input.length());
} catch (FileNotFoundException e) {
throw new HttpRequestException(e);
}
return send(stream);
}
/**
* Write byte array to request body
*
* @param input
* @return this request
* @throws HttpRequestException
*/
public HttpRequest send(final byte[] input) throws HttpRequestException {
if (input != null)
incrementTotalSize(input.length);
return send(new ByteArrayInputStream(input));
}
/**
* Write stream to request body
* <p>
* 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
* <p>
* 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<HttpRequest>(writer) {
@Override
protected HttpRequest run() throws IOException {
return copy(input, writer);
}
}.call();
}
/**
* Write char sequence to request body
* <p>
* 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
* <p>
* 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
* <p>
* 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
* <p>
* 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
* <p>
* 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
* <p>
* 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;
}
charset = getValidCharset(charset);
try {
openOutput();
if (!first)
output.write('&');
output.write(URLEncoder.encode(name.toString(), charset));
output.write('=');
if (value != null)
output.write(URLEncoder.encode(value.toString(), charset));
} 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
* <p>
* 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 <code>true</code> for each
* host verified
* <p>
* 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;
}
}

评论列表( 0 )

你可以在登录后,发表评论

搜索帮助