Java tutorial
/* * LumaQQ - Java QQ Client * * Copyright (C) 2004 luma <stubma@163.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package edu.tsinghua.lumaqq.qq.net; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import edu.tsinghua.lumaqq.qq.QQ; import edu.tsinghua.lumaqq.qq.packets.PacketParseException; /** * <pre> * Http??HTTP??TCP? * ?TCP?443? * </pre> * * @see RFC 2616 * @see RFC 2617 * @author luma */ public class HttpProxy extends AbstractProxy { /** Log */ private static final Log log = LogFactory.getLog(HttpProxy.class); /** ?? - ? */ public static final String SUCCESS = "200"; /** ?? - ?? */ public static final String NEED_AUTH = "407"; /** ? - */ public static final int STATUS_NONE = 0; /** ? - ? */ public static final int STATUS_INIT = 1; /** ? - ? */ public static final int STATUS_AUTH = 2; /** ? - Ready */ public static final int STATUS_READY = 3; /** CRLF */ private static final byte[] CRLF = "\r\n".getBytes(); /** CONNECT ?? */ private static final byte[] CONNECT_BEGIN = "CONNECT ".getBytes(); /** CONNECT ?? */ private static final byte[] CONNECT_END = " HTTP/1.1\r\n".getBytes(); /** Accept Header */ private static final byte[] ACCEPT = "Accept: */*\r\n".getBytes(); /** Content-Type Header */ private static final byte[] CONTENT_TYPE = "Content-Type: text/html\r\n".getBytes(); /** Proxy-Connection Header */ private static final byte[] PROXY_CONNECTION = "Proxy-Connection: Keep-Alive\r\n".getBytes(); /** Content-lenght Header */ private static final byte[] CONTENT_LENGTH = "Content-length: 0\r\n".getBytes(); /** Basic Proxy-Authorization Header */ private static final byte[] PROXY_AUTHORIZATION = "Proxy-Authorization: Basic ".getBytes(); /** base64 ?? */ private static byte[] authParam; /** ??ip??? */ protected byte[] remoteAddress; /** * * * @throws IOException */ public HttpProxy(IProxyHandler handler) throws IOException { super(handler); status = STATUS_NONE; } /** * ?? * * @param u ?? * @param p ? * @throws IOException */ public HttpProxy(IProxyHandler handler, String u, String p) throws IOException { this(handler); username = u; password = p; if (u == null || "".equals(u.trim()) || p == null) authParam = null; else { Base64 codec = new Base64(); authParam = new String(codec.encode((u + ":" + p).getBytes())).getBytes(); } } /* (non-Javadoc) * @see edu.tsinghua.lumaqq.qq.IProxy#init() */ public void init() { log.trace("HttpProxy init"); // buffer.clear(); buffer.put(CONNECT_BEGIN).put(remoteAddress).put(CONNECT_END).put(ACCEPT).put(CONTENT_TYPE) .put(PROXY_CONNECTION).put(CONTENT_LENGTH).put(CRLF); // ?? buffer.flip(); send(); status = STATUS_INIT; } /** * ? */ private void auth() { log.trace("HttpProxy auth"); // buffer.clear(); buffer.put(CONNECT_BEGIN).put(remoteAddress).put(CONNECT_END).put(PROXY_AUTHORIZATION).put(authParam) .put(CRLF).put(ACCEPT).put(CONTENT_TYPE).put(PROXY_CONNECTION).put(CONTENT_LENGTH).put(CRLF); // ?? buffer.flip(); send(); status = STATUS_AUTH; } /* (non-Javadoc) * @see edu.tsinghua.lumaqq.qq.INIOHandler#processRead(java.nio.channels.SelectionKey) */ public void processRead(SelectionKey sk) throws IOException, PacketParseException { log.trace("HttpProxy NIOHandler processRead"); // ? receive(); // byte[] b = new byte[buffer.limit()]; buffer.get(b); String response = new String(b); log.debug(response); if (!response.startsWith("HTTP/1.")) return; // ? String replyCode = response.substring(9, 12); switch (status) { case STATUS_INIT: if (SUCCESS.equals(replyCode)) { /* ? */ log.debug("?"); status = STATUS_READY; handler.proxyReady(null); } else if (NEED_AUTH.equals(replyCode)) { /* ?? */ log.debug("???????"); handler.proxyError("Proxy Need Auth"); } else { log.debug("??"); handler.proxyError("Unknown Reply Code"); } break; case STATUS_AUTH: if (SUCCESS.equals(replyCode)) { /* ? */ log.debug("?"); status = STATUS_READY; handler.proxyReady(null); } else if (NEED_AUTH.equals(replyCode)) { /* ?????? */ log.debug("?????"); handler.proxyAuthFail(); } else { log.debug("??"); handler.proxyError("Unknown Reply Code"); } break; default: break; } } /* (non-Javadoc) * @see edu.tsinghua.lumaqq.qq.INIOHandler#processWrite() */ public void processWrite() throws IOException { log.trace("HttpProxy processWrite"); if (connected) { if (authParam == null) init(); else auth(); } } /* (non-Javadoc) * @see edu.tsinghua.lumaqq.qq.IProxy#setServerAddress(java.net.InetSocketAddress) */ @Override public void setRemoteAddress(InetSocketAddress serverAddress) { super.setRemoteAddress(serverAddress); String s = serverAddress.getHostName() + ':' + QQ.QQ_PORT_HTTP; this.remoteAddress = s.getBytes(); } }