package net.i2p.sam; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.net.Socket; import java.net.SocketException; import java.net.SocketTimeoutException; /** * Modified from I2PTunnelHTTPServer * Handles UTF-8. Does not buffer past the end of line. * * @since 0.9.24 */ class ReadLine { private static final int MAX_LINE_LENGTH = 8*1024; /** * Read a line teriminated by newline, with a total read timeout. * * Warning - strips \n but not \r * Warning - 8KB line length limit as of 0.7.13, @throws IOException if exceeded * * @param buf output * @param timeout forever if if zero or negative * @throws SocketTimeoutException if timeout is reached before newline * @throws EOFException if EOF is reached before newline * @throws LineTooLongException if too long * @throws IOException on other errors in the underlying stream */ public static void readLine(Socket socket, StringBuilder buf, int timeout) throws IOException { final int origTimeout = timeout; int c; int i = 0; final long expires; if (origTimeout > 0) { socket.setSoTimeout(timeout); expires = System.currentTimeMillis() + timeout; } else { expires = 0; } final Reader reader = new UTF8Reader(socket.getInputStream()); while ( (c = reader.read()) != -1) { if (++i > MAX_LINE_LENGTH) throw new LineTooLongException("Line too long - max " + MAX_LINE_LENGTH); if (c == '\n') break; if (origTimeout > 0) { int newTimeout = (int) (expires - System.currentTimeMillis()); if (newTimeout <= 0) throw new SocketTimeoutException(); buf.append((char)c); if (newTimeout != timeout) { timeout = newTimeout; socket.setSoTimeout(timeout); } } else { buf.append((char)c); } } if (c == -1) { if (origTimeout > 0 && System.currentTimeMillis() >= expires) throw new SocketTimeoutException(); else throw new EOFException(); } } private static class LineTooLongException extends IOException { public LineTooLongException(String s) { super(s); } } }