Java tutorial
/* * Copyright 2002-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.pdark.dsmp; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.SystemUtils; import org.apache.log4j.Logger; import org.codehaus.plexus.digest.DigesterException; import org.codehaus.plexus.digest.Md5Digester; import org.codehaus.plexus.digest.Sha1Digester; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.SocketException; import java.net.URL; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; /** * Handle a connection from a maven. * * @author digulla * */ public class RequestHandler extends Thread { public static final Logger log = Logger.getLogger(RequestHandler.class); public static final Logger downloadLog = Logger.getLogger("downloadLog"); private final Socket clientSocket; private final Config config; public RequestHandler(Socket clientSocket, Config config) { this.clientSocket = clientSocket; this.config = config; } @Override public void run() { if (clientSocket == null) throw new RuntimeException("Connection is already closed"); try { log.debug("Got connection from " + clientSocket.getInetAddress()); String line; boolean keepAlive = false; boolean headOnly = false; do { String downloadURL = null; StringBuffer fullRequest = new StringBuffer(1024); while ((line = readLine()) != null) { if (line.length() == 0) break; log.debug("Got: " + line); fullRequest.append(line); fullRequest.append('\n'); if ("Proxy-Connection: keep-alive".equals(line)) keepAlive = true; if (line.startsWith("GET ")) { int pos = line.lastIndexOf(' '); line = line.substring(4, pos); downloadURL = line; } if (line.startsWith("HEAD ")) { int pos = line.lastIndexOf(' '); line = line.substring(4, pos); downloadURL = line; headOnly = true; } } if (downloadURL == null) { if (line == null) break; log.error("Found no URL to download in request:\n" + fullRequest.toString()); } else { log.info("Got request for " + downloadURL); serveURL(downloadURL, headOnly); } } while (line != null && keepAlive); log.debug("Terminating connection with " + clientSocket.getInetAddress()); } catch (Exception e) { log.error("Conversation with client aborted", e); } finally { close(); } } public void close() { try { if (out != null) out.close(); } catch (Exception e) { log.error("Exception while closing the outputstream", e); } out = null; try { if (in != null) in.close(); } catch (Exception e) { log.error("Exception while closing the inputstream", e); } in = null; try { if (clientSocket != null) clientSocket.close(); } catch (Exception e) { log.error("Exception while closing the socket", e); } } private void serveURL(String downloadURL, boolean headOnly) throws IOException { URL url = new URL(downloadURL); url = config.getMirror(url); if (!"http".equals(url.getProtocol())) throw new IOException("Can only handle HTTP requests, got " + downloadURL); File f = getPatchFile(url); if (!f.exists()) f = getCacheFile(url, config.getCacheDirectory()); if (!f.exists()) { ProxyDownload d = new ProxyDownload(url, f, config); try { d.download(); } catch (DownloadFailed e) { log.error(e.getMessage()); println(e.getStatusLine()); println(); getOut().flush(); return; } } else { log.debug("Serving from local cache " + f.getAbsolutePath()); } println("HTTP/1.1 200 OK"); print("Date: "); Date d = new Date(f.lastModified()); println(INTERNET_FORMAT.format(d)); print("Content-length: "); println(String.valueOf(f.length())); print("Content-type: "); String ext = StringUtils.substringAfterLast(downloadURL, ".").toLowerCase(); String type = CONTENT_TYPES.get(ext); if (type == null) { log.warn("Unknown extension " + ext + ". Using content type text/plain."); type = "text/plain"; } println(type); println(); if (headOnly) { log.info("HEAD for : " + url.toExternalForm()); downloadLog.info("Downloaded: " + url.toExternalForm()); return; } InputStream data = new BufferedInputStream(new FileInputStream(f)); IOUtils.copy(data, out); data.close(); downloadLog.info("Downloaded: " + url.toExternalForm()); } public File getPatchFile(URL url) { File dir = config.getPatchesDirectory(); File f = getCacheFile(url, dir); if (!f.exists()) { String ext = StringUtils.substringAfterLast(url.getPath(), ".").toLowerCase(); if ("md5".equals(ext) || "sha1".equals(ext)) { File source = new File(StringUtils.substringBeforeLast(f.getAbsolutePath(), ".")); if (source.exists()) { generateChecksum(source, f, ext); } } } return f; } public static void generateChecksum(File source, File f, String ext) { try { String checksum = null; if ("md5".equals(ext)) { Md5Digester digester = new Md5Digester(); checksum = digester.calc(source); } else if ("sha1".equals(ext)) { Sha1Digester digester = new Sha1Digester(); checksum = digester.calc(source); } if (checksum != null) { FileWriter w = new FileWriter(f); w.write(checksum); w.write(SystemUtils.LINE_SEPARATOR); w.close(); } } catch (DigesterException e) { log.warn("Error creating " + ext.toUpperCase() + " checksum for " + source.getAbsolutePath(), e); } catch (IOException e) { log.warn("Error writing " + ext.toUpperCase() + " checksum for " + source.getAbsolutePath() + " to " + f.getAbsolutePath(), e); } } public static File getCacheFile(URL url, File root) { root = new File(root, url.getHost()); if (url.getPort() != -1 && url.getPort() != 80) root = new File(root, String.valueOf(url.getPort())); File f = new File(root, url.getPath()); return f; } public final static HashMap<String, String> CONTENT_TYPES = new HashMap<String, String>(); static { CONTENT_TYPES.put("xml", "application/xml"); CONTENT_TYPES.put("pom", "application/xml"); CONTENT_TYPES.put("jar", "application/java-archive"); CONTENT_TYPES.put("md5", "text/plain"); CONTENT_TYPES.put("sha1", "text/plain"); CONTENT_TYPES.put("asc", "text/plain"); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); CONTENT_TYPES.put("", ""); } private final static SimpleDateFormat INTERNET_FORMAT = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss zzz"); private byte[] NEW_LINE = new byte[] { '\r', '\n' }; private void println(String string) throws IOException { print(string); println(); } private void println() throws IOException { getOut().write(NEW_LINE); } private void print(String string) throws IOException { getOut().write(string.getBytes("ISO-8859-1")); } private OutputStream out; protected OutputStream getOut() throws IOException { if (out == null) out = new BufferedOutputStream(clientSocket.getOutputStream()); return out; } private BufferedInputStream in; private String readLine() throws IOException { if (in == null) in = new BufferedInputStream(clientSocket.getInputStream()); StringBuffer buffer = new StringBuffer(256); int c; try { while ((c = in.read()) != -1) { if (c == '\r') continue; if (c == '\n') break; buffer.append((char) c); } } catch (SocketException e) { if ("Connection reset".equals(e.getMessage())) return null; throw e; } if (c == -1) return null; if (buffer.length() == 0) return ""; return buffer.toString(); } }