001: package br.com.igor.proxy.http;
002:
003: import java.io.File;
004: import java.io.FileNotFoundException;
005: import java.io.IOException;
006: import java.io.InputStream;
007:
008: import org.apache.commons.httpclient.Cookie;
009: import org.apache.commons.httpclient.DefaultMethodRetryHandler;
010: import org.apache.commons.httpclient.Header;
011: import org.apache.commons.httpclient.HttpClient;
012: import org.apache.commons.httpclient.HttpMethodBase;
013: import org.apache.commons.httpclient.HttpStatus;
014: import org.apache.commons.httpclient.NameValuePair;
015: import org.apache.commons.httpclient.UsernamePasswordCredentials;
016: import org.apache.commons.httpclient.methods.GetMethod;
017: import org.apache.commons.httpclient.methods.PostMethod;
018: import org.apache.commons.httpclient.methods.multipart.FilePart;
019: import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
020: import org.apache.commons.httpclient.methods.multipart.Part;
021: import org.apache.commons.httpclient.methods.multipart.StringPart;
022: import org.apache.commons.httpclient.params.HttpMethodParams;
023:
024: /**
025: * Esta classe é uma implementação da interface {@link HttpClient}. Atualmente utiliza as bibliotecas
026: * "commons-httpclient" do projeto Jakarta, mas pode vir a ser implementada de outra forma.
027: * <p>
028: *
029: * INFORMACOES ADICIONAIS PARA COMUNICACAO HTTPS:
030: * <p>
031: * A implementação prove suporte transparente 'a comunicacao SSL utilizando o mecanismo padrao (JSSE).
032: * <p>
033: * Para tanto,basta que a JVM cliente esteja configurada para acessar um repositorio de certificados raiz confiaveis
034: * (certificados das CA).
035: * <p>
036: * Uma forma de gerar esse repositorio e' obter os certificados raiz confiaveis a partir do MS-Internet Explorer:
037: * <p>
038: * -Menu Ferramentas/Opcoes da Internet/Conteudo/Certificados
039: * <p>
040: * -aba Autoridades de certificacao raiz confiaveis
041: * <p>
042: * -botao Avancado: X509 binario codificado por DER
043: * <p>
044: * -selecionar os certificados desejados e arrastar com o mouse para uma pasta)
045: * <p>
046: * Ex: Os certificados do BB sao assinados pela
047: * <p>
048: * autoridade VeriSign Class 3 Code Signing 2001 CA
049: * <p>
050: * Substituir cada %1 abaixo pelo nome do certificado *.cer exportado acima:
051: * <p>
052: * Utilizar a ferramenta 'keytool' do java para criar um repositorio e importar os certificados:
053: * <p>
054: * keytool -import -trustcacerts -file %1 -keystore trusts.keystore -storepass password -alias %1
055: * <p>
056: * Finalmente, utilizar o arquivo trusts.keystore como sendo o repositorio
057: * <p>
058: * de certificados confiáveis, por meio das variaveis de ambiente abaixo:
059: * <p>
060: *
061: * java -Djavax.net.ssl.trustStore=c:\trusts.keystore
062: * <p>
063: * -Djavax.net.ssl.trustStorePassword=password
064: * <p>
065: *
066: * Com essas providencias, o acesso via HTTPS sera' totalmente automatico, basta utilizar uma URL iniciando com o
067: * protocolo "https://..."
068: * <p>
069: *
070: * OBSERVAÇÃO: Para ambientes com JVM < 1.4.x (tal como OS/2), os pacotes da JSSE precisam ter sido instalados
071: * manualmente.
072: * <p>
073: * Veja: {@link http://java.sun.com/products/jsse/doc/guide/API_users_guide.html#Installation}
074: *
075: */
076: @SuppressWarnings("deprecation")
077: public class HttpClientDefault implements GeneralHttpClient {
078:
079: private int INDETERMINADO = 0;
080:
081: private int INICIALIZADO = 1;
082:
083: private int EXECUTADO = 2;
084:
085: HttpClient client = null;
086:
087: HttpMethodBase method = null;
088:
089: String url = null;
090:
091: Cookie cookie = null;
092:
093: DefaultMethodRetryHandler retryhandler;
094:
095: int methodType;
096:
097: int timeout;
098:
099: int retryCount;
100:
101: int estado;
102:
103: /**
104: * Cria uma instancia e configura algumas propriedades default:
105: * <p>
106: * timeout = 5000 ms (5 s);
107: * <p>
108: * retry count = 0 (desabilitado);
109: * <p>
110: * metodo = GET
111: *
112: * @param url string contendo uma URL completa.
113: * <p>
114: * Deve conter inclusive o campo protocolo. Ex: http://www.apache.org
115: * @see #setTimeout(int)
116: * @see #setMethod(int)
117: * @see #setRetryCount(int)
118: */
119: protected HttpClientDefault() {
120: this .client = new HttpClient(); // atualmente delegamos a esta implementacao
121: setRetryCount(0);
122: setTimeout(5000);
123: retryhandler = new DefaultMethodRetryHandler();
124: estado = INDETERMINADO;
125: }
126:
127: /*
128: * (non-Javadoc)
129: *
130: * @see HttpClientGA#setTimeout(int)
131: */
132: public void setTimeout(int t) {
133: }
134:
135: private void criarMetodo() {
136: if (methodType == HTTPCLIENT_POST_METHOD) {
137: method = new PostMethod(url);
138: } else { // padrao é GET
139: method = new GetMethod(url);
140: }
141: }
142:
143: // configuracoes relativas ao client e ao method
144: private void configurar() {
145: // configura o retry count:
146: if (retryCount > 0) {
147: retryhandler.setRequestSentRetryEnabled(true);
148: } else {
149: retryhandler.setRequestSentRetryEnabled(false);
150: }
151: retryhandler.setRetryCount(retryCount);
152: method.setMethodRetryHandler(retryhandler);
153: // configura o timeout:
154: client.setTimeout(timeout);
155: method.setFollowRedirects(false);
156: }
157:
158: /*
159: * (non-Javadoc)
160: *
161: * @see HttpClientGA#setRetryCount(int)
162: */
163: public void setRetryCount(int c) {
164: retryCount = c;
165: }
166:
167: /*
168: * (non-Javadoc)
169: *
170: * @see HttpClientGA#addPostParameter(java.lang.String, java.lang.String)
171: */
172: public void addPostParameter(String name, String value) {
173: checkEstadoInicializado();
174: if (this .method instanceof PostMethod) {
175: PostMethod pm = (PostMethod) this .method;
176: pm.addParameter(name, value);
177: }
178: }
179:
180: /*
181: * (non-Javadoc)
182: *
183: * @see HttpClientGA#addPostParameter(NameValue)
184: */
185: public void addPostParameter(NameValue[] nv) {
186: checkEstadoInicializado();
187: if (this .method instanceof PostMethod) {
188: PostMethod pm = (PostMethod) this .method;
189: for (int i = 0; i < nv.length; i++) {
190: pm.addParameter(nv[i].getName(), nv[i].getValue());
191: }
192: }
193: }
194:
195: /*
196: * (non-Javadoc)
197: *
198: * @see HttpClientGA#addRequestHeader(String, String)
199: */
200: public void addRequestHeader(String name, String value) {
201: checkEstadoInicializado();
202: method.addRequestHeader(name, value);
203: }
204:
205: /*
206: * (non-Javadoc)
207: *
208: * @see HttpClientGA#addRequestHeader(NameValue)
209: */
210: public void addRequestHeader(NameValue[] nv) {
211: checkEstadoInicializado();
212: for (int i = 0; i < nv.length; i++) {
213: method.addRequestHeader(nv[i].getName(), nv[i].getValue());
214: }
215: }
216:
217: /*
218: * (non-Javadoc)
219: *
220: * @see HttpClientGA#setPostRequestBody(String)
221: */
222: public void setPostRequestBody(String body) {
223: checkEstadoInicializado();
224: if (this .method instanceof PostMethod) {
225: PostMethod pm = (PostMethod) this .method;
226: pm.setRequestBody(body);
227: pm.setRequestContentLength(body.length());
228: }
229: }
230:
231: public void initRequest(String url, int methodType) {
232: this .methodType = methodType;
233: this .url = url;
234: // libera conexao e recursos mantidos pelo objeto 'method' anterior se houver
235: if (method != null) {
236: // A conexao e' liberada para um pool e podera ser
237: // reutilizada novamente quando usada por outros
238: // objetos "Method" no mesmo client:
239: method.releaseConnection();
240: }
241: // precisamos criar um novo objeto "Method" para cada
242: // chamada a executeMethod, senao ocorre exception:
243: criarMetodo();
244: estado = INICIALIZADO;
245: }
246:
247: private void checkEstadoInicializado() {
248: if (this .estado != INICIALIZADO) {
249: throw new RuntimeException(
250: "Estado invalido: necessario execucao previa de initRequest()");
251: }
252: }
253:
254: private void checkEstadoExecutado() {
255: if (this .estado != EXECUTADO) {
256: throw new RuntimeException(
257: "Estado invalido: necessario execucao previa de executeRequest()");
258: }
259: }
260:
261: /*
262: * (non-Javadoc)
263: *
264: * @see HttpClientGA#execute()
265: */
266: public int executeRequest() throws IOException {
267: checkEstadoInicializado();
268: configurar();
269: int ret = 0;
270: client.getState().addCookie(cookie);
271: try {
272: ret = client.executeMethod(method);
273: } catch (Exception e) {
274: // Logger.getLogger("log").error("HttpClientGADefault.execute() -
275: // Erro de E/S: " + e.getMessage());
276: if (e instanceof IOException) {
277: throw (IOException) e;
278: } else {
279: throw new IOException("Erro: " + e.getMessage());
280: }
281: }
282: // trata redirecionamento da url:
283: // CUIDADO ISSO PODE CAUSAR LOOP - A RESOLVER
284: if (ret == HttpStatus.SC_MOVED_PERMANENTLY
285: || ret == HttpStatus.SC_MOVED_TEMPORARILY
286: || ret == HttpStatus.SC_TEMPORARY_REDIRECT) {
287: Header locationHeader = method
288: .getResponseHeader("location");
289: if (locationHeader != null) { // se foi informada nova url
290: url = locationHeader.getValue(); // substitui a atual
291: initRequest(url, this .methodType);
292: ret = executeRequest(); // e re-executa a requisicao
293: }
294: }
295: if (client.getState().getCookies().length > 0) {
296: cookie = client.getState().getCookies()[0];
297: }
298: estado = EXECUTADO;
299: return ret;
300: }
301:
302: /*
303: * (non-Javadoc)
304: *
305: * @see HttpClientGA#getStatusCode()
306: */
307: public int getStatusCode() {
308: checkEstadoExecutado();
309: return method.getStatusCode();
310: }
311:
312: /*
313: * (non-Javadoc)
314: *
315: * @see HttpClientGA#getStatusPhrase()
316: */
317: public String getStatusPhrase() {
318: checkEstadoExecutado();
319: return method.getStatusLine().getReasonPhrase();
320: }
321:
322: /*
323: * (non-Javadoc)
324: *
325: * @see HttpClientGA#getResponseBody()
326: */
327: public String getResponseBody() throws IOException {
328: checkEstadoExecutado();
329: String s = method.getResponseBodyAsString();
330: if (s == null) {
331: throw new IOException(
332: "Erro em HttpClientGADefault.getResponseBody(): retornou null");
333: }
334: return s;
335: }
336:
337: /*
338: * (non-Javadoc)
339: *
340: * @see HttpClientGA#getResponseBodyAsStream()
341: */
342: public InputStream getResponseBodyAsStream() throws IOException {
343: checkEstadoExecutado();
344: return method.getResponseBodyAsStream();
345: }
346:
347: /*
348: * (non-Javadoc)
349: *
350: * @see HttpClientGA#getResponseFooters()
351: */
352: public NameValue[] getResponseFooters() throws IOException {
353: checkEstadoExecutado();
354: Header[] h = method.getResponseFooters();
355: return getNameValues(h);
356: }
357:
358: /*
359: * (non-Javadoc)
360: *
361: * @see HttpClientGA#getResponseFooters()
362: */
363: public String getResponseFootersAsString() throws IOException {
364: Header[] h = method.getResponseFooters();
365: return getAsString(h);
366: }
367:
368: /*
369: * (non-Javadoc)
370: *
371: * @see HttpClientGA#getResponseFooters()
372: */
373: public String getResponseHeadersAsString() throws IOException {
374: checkEstadoExecutado();
375: Header[] h = method.getResponseHeaders();
376: return getAsString(h);
377: }
378:
379: /*
380: * (non-Javadoc)
381: *
382: * @see HttpClientGA#getResponseHeaders()
383: */
384: public NameValue[] getResponseHeaders() throws IOException {
385: checkEstadoExecutado();
386: Header[] h = method.getResponseHeaders();
387: return getNameValues(h);
388: }
389:
390: private NameValue[] getNameValues(Header[] headers) {
391: NameValue[] ret = new NameValue[headers.length];
392: for (int j = 0; j < headers.length; j++) {
393: ret[j] = new NameValue(headers[j].getName(), headers[j]
394: .getValue());
395: }
396: return ret;
397: }
398:
399: private String getAsString(Header[] headers) {
400: StringBuffer s = new StringBuffer();
401: for (int j = 0; j < headers.length; j++) {
402: s.append(headers[j].getName() + ":" + headers[j].getValue()
403: + "\n");
404: }
405: return s.toString();
406: }
407:
408: /*
409: * (non-Javadoc)
410: *
411: * @see HttpClientGA#setProxyAuthorization(java.lang.String, int, java.lang.String, java.lang.String)
412: */
413: public void setProxyAuthorization(String host, int port,
414: String user, String passwd) {
415: client.getHostConfiguration().setProxy(host, port);
416: client.getState().setProxyCredentials(null, null,
417: new UsernamePasswordCredentials(user, passwd));
418: }
419:
420: /*
421: * (non-Javadoc)
422: *
423: * @see HttpClientGA#setServerAuthorization(java.lang.String, java.lang.String)
424: */
425: public void setServerAuthorization(String user, String passwd) {
426: client.getState().setCredentials(null, null,
427: new UsernamePasswordCredentials(user, passwd));
428:
429: }
430:
431: public void setProxy(String ip, int port) {
432: client.getHostConfiguration().setProxy(ip, port);
433: }
434:
435: /**
436: * Tem que ser o ultimo método a ser
437: * chamado para adcionar parametros ao post
438: * @param targetFile
439: * @throws FileNotFoundException
440: */
441: public void fileUpload(String paraName, File targetFile)
442: throws FileNotFoundException {
443: if (!(this .method instanceof PostMethod))
444: throw new IllegalArgumentException(
445: "The current method is not POST, you can't upload files!");
446: PostMethod filePost = (PostMethod) this .method;
447:
448: NameValuePair[] params = filePost.getParameters();
449:
450: filePost.getParams().setBooleanParameter(
451: HttpMethodParams.USE_EXPECT_CONTINUE, false);
452: Part[] parts = new Part[params.length + 1];
453: parts[0] = new FilePart(paraName, targetFile);
454: int i = 1;
455: for (NameValuePair part : params)
456: parts[i++] = new StringPart(part.getName(), part.getValue());
457: filePost.setRequestEntity(new MultipartRequestEntity(parts,
458: filePost.getParams()));
459: client.getHttpConnectionManager().getParams()
460: .setConnectionTimeout(5000);
461: }
462: }
|