Changeset f7577e7


Ignore:
Timestamp:
Apr 4, 2015 7:12:18 PM (6 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
bb082c35
Parents:
b5df13d
Message:

i2ptunnel: Return specific error pages to client on errors
in HTTP header processing in the HTTP server (ticket #1507)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java

    rb5df13d rf7577e7  
    122122         "<p>This I2P website is not configured for SSL.</p>\n" +
    123123         "</body></html>";
     124
     125    private final static String ERR_REQUEST_URI_TOO_LONG =
     126         "HTTP/1.1 414 Request URI too long\r\n"+
     127         "Content-Type: text/html; charset=iso-8859-1\r\n"+
     128         "Cache-control: no-cache\r\n"+
     129         "Connection: close\r\n"+
     130         "Proxy-Connection: close\r\n"+
     131         "\r\n"+
     132         "<html><head><title>414 Request URI Too Long</title></head>\n"+
     133         "<body><h2>414 Request URI too long</h2>\n" +
     134         "</body></html>";
     135
     136    private final static String ERR_HEADERS_TOO_LARGE =
     137         "HTTP/1.1 431 Request header fields too large\r\n"+
     138         "Content-Type: text/html; charset=iso-8859-1\r\n"+
     139         "Cache-control: no-cache\r\n"+
     140         "Connection: close\r\n"+
     141         "Proxy-Connection: close\r\n"+
     142         "\r\n"+
     143         "<html><head><title>431 Request Header Fields Too Large</title></head>\n"+
     144         "<body><h2>431 Request header fields too large</h2>\n" +
     145         "</body></html>";
     146
     147    private final static String ERR_REQUEST_TIMEOUT =
     148         "HTTP/1.1 408 Request timeout\r\n"+
     149         "Content-Type: text/html; charset=iso-8859-1\r\n"+
     150         "Cache-control: no-cache\r\n"+
     151         "Connection: close\r\n"+
     152         "Proxy-Connection: close\r\n"+
     153         "\r\n"+
     154         "<html><head><title>408 Request Timeout</title></head>\n"+
     155         "<body><h2>408 Request timeout</h2>\n" +
     156         "</body></html>";
     157
     158    private final static String ERR_BAD_REQUEST =
     159         "HTTP/1.1 400 Bad Request\r\n"+
     160         "Content-Type: text/html; charset=iso-8859-1\r\n"+
     161         "Cache-control: no-cache\r\n"+
     162         "Connection: close\r\n"+
     163         "Proxy-Connection: close\r\n"+
     164         "\r\n"+
     165         "<html><head><title>400 Bad Request</title></head>\n"+
     166         "<body><h2>400 Bad request</h2>\n" +
     167         "</body></html>";
     168
    124169
    125170    public I2PTunnelHTTPServer(InetAddress host, int port, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
     
    243288
    244289            StringBuilder command = new StringBuilder(128);
    245             Map<String, List<String>> headers = readHeaders(socket, null, command,
    246                 CLIENT_SKIPHEADERS, getTunnel().getContext());
     290            Map<String, List<String>> headers;
     291            try {
     292                // catch specific exceptions thrown, to return a good
     293                // error to the client
     294                headers = readHeaders(socket, null, command,
     295                                      CLIENT_SKIPHEADERS, getTunnel().getContext());
     296            } catch (SocketTimeoutException ste) {
     297                try {
     298                    socket.getOutputStream().write(ERR_REQUEST_TIMEOUT.getBytes("UTF-8"));
     299                } catch (IOException ioe) {
     300                } finally {
     301                     try { socket.close(); } catch (IOException ioe) {}
     302                }
     303                if (_log.shouldLog(Log.WARN))
     304                    _log.warn("Error while receiving the new HTTP request", ste);
     305                return;
     306            } catch (EOFException eofe) {
     307                try {
     308                    socket.getOutputStream().write(ERR_BAD_REQUEST.getBytes("UTF-8"));
     309                } catch (IOException ioe) {
     310                } finally {
     311                     try { socket.close(); } catch (IOException ioe) {}
     312                }
     313                if (_log.shouldLog(Log.WARN))
     314                    _log.warn("Error while receiving the new HTTP request", eofe);
     315                return;
     316            } catch (LineTooLongException ltle) {
     317                try {
     318                    socket.getOutputStream().write(ERR_HEADERS_TOO_LARGE.getBytes("UTF-8"));
     319                } catch (IOException ioe) {
     320                } finally {
     321                     try { socket.close(); } catch (IOException ioe) {}
     322                }
     323                if (_log.shouldLog(Log.WARN))
     324                    _log.warn("Error while receiving the new HTTP request", ltle);
     325                return;
     326            } catch (RequestTooLongException rtle) {
     327                try {
     328                    socket.getOutputStream().write(ERR_REQUEST_URI_TOO_LONG.getBytes("UTF-8"));
     329                } catch (IOException ioe) {
     330                } finally {
     331                     try { socket.close(); } catch (IOException ioe) {}
     332                }
     333                if (_log.shouldLog(Log.WARN))
     334                    _log.warn("Error while receiving the new HTTP request", rtle);
     335                return;
     336            } catch (BadRequestException bre) {
     337                try {
     338                    socket.getOutputStream().write(ERR_BAD_REQUEST.getBytes("UTF-8"));
     339                } catch (IOException ioe) {
     340                } finally {
     341                     try { socket.close(); } catch (IOException ioe) {}
     342                }
     343                if (_log.shouldLog(Log.WARN))
     344                    _log.warn("Error while receiving the new HTTP request", bre);
     345                return;
     346            }
    247347            long afterHeaders = getTunnel().getContext().clock().now();
    248348
     
    710810     *  @param in if null, use socket.getInputStream() as InputStream
    711811     *  @param command out parameter, first line
    712      *  @param command out parameter, first line
    713812     *  @throws SocketTimeoutException if timeout is reached before newline
    714813     *  @throws EOFException if EOF is reached before newline
    715      *  @throws LineTooLongException if too long
     814     *  @throws LineTooLongException if one header too long, or too many headers
     815     *  @throws RequestTooLongException if too long
     816     *  @throws BadRequestException on bad headers
    716817     *  @throws IOException on other errors in the underlying stream
    717818     */
     
    724825        long expire = ctx.clock().now() + TOTAL_HEADER_TIMEOUT;
    725826        if (socket != null) {
    726             readLine(socket, command, HEADER_TIMEOUT);
     827            try {
     828                readLine(socket, command, HEADER_TIMEOUT);
     829            } catch (LineTooLongException ltle) {
     830                // convert for first line
     831                throw new RequestTooLongException("Request too long - max " + MAX_LINE_LENGTH);
     832            }
    727833        } else {
    728834             boolean ok = DataHelper.readLine(in, command);
    729835             if (!ok)
    730                  throw new IOException("EOF reached before the end of the headers [" + buf.toString() + "]");
     836                 throw new EOFException("EOF reached before the end of the headers [" + buf.toString() + "]");
    731837        }
    732838       
     
    750856        int i = 0;
    751857        while (true) {
    752             if (++i > MAX_HEADERS)
    753                 throw new IOException("Too many header lines - max " + MAX_HEADERS);
     858            if (++i > MAX_HEADERS) {
     859                throw new LineTooLongException("Too many header lines - max " + MAX_HEADERS);
     860            }
    754861            buf.setLength(0);
    755862            if (socket != null) {
     
    758865                 boolean ok = DataHelper.readLine(in, buf);
    759866                 if (!ok)
    760                      throw new IOException("EOF reached before the end of the headers [" + buf.toString() + "]");
     867                     throw new BadRequestException("EOF reached before the end of the headers [" + buf.toString() + "]");
    761868            }
    762869            if ( (buf.length() == 0) ||
     
    765872                return headers;
    766873            } else {
    767                 if (ctx.clock().now() >= expire)
    768                     throw new IOException("Headers took too long [" + buf.toString() + "]");
     874                if (ctx.clock().now() > expire) {
     875                    throw new SocketTimeoutException("Headers took too long [" + buf.toString() + "]");
     876                }
    769877                int split = buf.indexOf(":");
    770                 if (split <= 0) throw new IOException("Invalid HTTP header, missing colon [" + buf.toString() + "]");
     878                if (split <= 0) throw new BadRequestException("Invalid HTTP header, missing colon [" + buf.toString() + "]");
    771879                String name = buf.substring(0, split).trim();
    772880                String value = null;
     
    861969        }
    862970    }
     971
     972    /**
     973     *  @since 0.9.20
     974     */
     975    private static class RequestTooLongException extends IOException {
     976        public RequestTooLongException(String s) {
     977            super(s);
     978        }
     979    }
     980
     981    /**
     982     *  @since 0.9.20
     983     */
     984    private static class BadRequestException extends IOException {
     985        public BadRequestException(String s) {
     986            super(s);
     987        }
     988    }
    863989}
    864990
Note: See TracChangeset for help on using the changeset viewer.