Susimail, Console, Jetty:

- Adjust multipart size limits
- Better handling of errors when multipart limits are exceeded
- Fix multipart config for /configplugins
- Test for total size limit in susimail
This commit is contained in:
zzz
2017-12-05 21:46:11 +00:00
parent d4bafaeee8
commit f5dffb0726
7 changed files with 86 additions and 19 deletions

View File

@ -101,6 +101,7 @@ public class RequestWrapper {
/** /**
* @return List of request parameter names * @return List of request parameter names
* @throws IllegalStateException if the request is too large
*/ */
public Enumeration<String> getParameterNames() { public Enumeration<String> getParameterNames() {
if (isMultiPartRequest) { if (isMultiPartRequest) {
@ -117,6 +118,7 @@ public class RequestWrapper {
log(se); log(se);
} catch (IllegalStateException ise) { } catch (IllegalStateException ise) {
log(ise); log(ise);
throw ise;
} }
} }
return cachedParameterNames.keys(); return cachedParameterNames.keys();
@ -139,6 +141,9 @@ public class RequestWrapper {
return httpRequest.getContentType(); return httpRequest.getContentType();
} }
/**
* @throws IllegalStateException if the request is too large
*/
public String getContentType( String partName ) public String getContentType( String partName )
{ {
String result = null; String result = null;
@ -153,6 +158,7 @@ public class RequestWrapper {
log(se); log(se);
} catch (IllegalStateException ise) { } catch (IllegalStateException ise) {
log(ise); log(ise);
throw ise;
} }
} }
return result; return result;
@ -162,6 +168,9 @@ public class RequestWrapper {
return httpRequest.getAttribute( string ); return httpRequest.getAttribute( string );
} }
/**
* @throws IllegalStateException if the request is too large
*/
public String getParameter( String name, String defaultValue ) public String getParameter( String name, String defaultValue )
{ {
String result = defaultValue; String result = defaultValue;
@ -192,6 +201,7 @@ public class RequestWrapper {
log(se); log(se);
} catch (IllegalStateException ise) { } catch (IllegalStateException ise) {
log(ise); log(ise);
throw ise;
} finally { } finally {
if (in != null) try { in.close(); } catch (IOException ioe) {} if (in != null) try { in.close(); } catch (IOException ioe) {}
} }
@ -204,6 +214,9 @@ public class RequestWrapper {
return result; return result;
} }
/**
* @throws IllegalStateException if the request is too large
*/
public String getFilename(String partName ) public String getFilename(String partName )
{ {
String result = null; String result = null;
@ -218,11 +231,15 @@ public class RequestWrapper {
log(se); log(se);
} catch (IllegalStateException ise) { } catch (IllegalStateException ise) {
log(ise); log(ise);
throw ise;
} }
} }
return result; return result;
} }
/**
* @throws IllegalStateException if the request is too large
*/
public InputStream getInputStream(String partName ) public InputStream getInputStream(String partName )
{ {
InputStream result = null; InputStream result = null;
@ -237,6 +254,7 @@ public class RequestWrapper {
log(se); log(se);
} catch (IllegalStateException ise) { } catch (IllegalStateException ise) {
log(ise); log(ise);
throw ise;
} }
} }
return result; return result;

View File

@ -9,6 +9,7 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** /**
* @since 0.9.14 * @since 0.9.14
@ -25,6 +26,14 @@ public class XSSFilter implements Filter {
@Override @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException { throws IOException, ServletException {
try {
chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response); chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
} catch (IllegalStateException ise) {
// Multipart form error, probably file too big
// We need to send the error quickly, if we just throw a ServletException,
// the data keeps coming and the connection gets reset.
// This way we at least get the error to the browser.
((HttpServletResponse)response).sendError(413, ise.getMessage());
}
} }
} }

View File

@ -448,7 +448,7 @@
<!-- Add multipart config to servlets that need them --> <!-- Add multipart config to servlets that need them -->
<property name="__match1" value="&lt;servlet-class&gt;net.i2p.router.web.jsp." /> <property name="__match1" value="&lt;servlet-class&gt;net.i2p.router.web.jsp." />
<property name="__match2" value="_jsp&lt;/servlet-class&gt;" /> <property name="__match2" value="_jsp&lt;/servlet-class&gt;" />
<property name="__class1" value="${__match1}configclients${__match2}" /> <property name="__class1" value="${__match1}configplugins${__match2}" />
<property name="__class2" value="${__match1}configfamily${__match2}" /> <property name="__class2" value="${__match1}configfamily${__match2}" />
<property name="__class3" value="${__match1}configreseed${__match2}" /> <property name="__class3" value="${__match1}configreseed${__match2}" />
<property name="__multipart" value="&#10; <property name="__multipart" value="&#10;

View File

@ -17,9 +17,10 @@
<servlet-name>SusiMail</servlet-name> <servlet-name>SusiMail</servlet-name>
<servlet-class>i2p.susi.webmail.WebMail</servlet-class> <servlet-class>i2p.susi.webmail.WebMail</servlet-class>
<multipart-config> <multipart-config>
<max-file-size>67108864</max-file-size> <!-- 23 MB. See SMTPClient for discussion -->
<max-request-size>67108864</max-request-size> <max-file-size>24117248</max-file-size>
<file-size-threshold>262144</file-size-threshold> <max-request-size>24117248</max-request-size>
<file-size-threshold>131072</file-size-threshold>
</multipart-config> </multipart-config>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>

View File

@ -72,6 +72,14 @@ public class Attachment {
return new FileInputStream(data); return new FileInputStream(data);
} }
/**
* The unencoded size
* @since 0.9.33
*/
public long getSize() {
return data.length();
}
/** /**
* Delete the data file * Delete the data file
* @since 0.9.33 * @since 0.9.33

View File

@ -1648,6 +1648,7 @@ public class WebMail extends HttpServlet
sessionObject.isMobile = isMobile; sessionObject.isMobile = isMobile;
if (isPOST) { if (isPOST) {
try {
String nonce = request.getParameter(SUSI_NONCE); String nonce = request.getParameter(SUSI_NONCE);
if (nonce == null || !sessionObject.isValidNonce(nonce)) { if (nonce == null || !sessionObject.isValidNonce(nonce)) {
// These two strings are already in the router console FormHandler, // These two strings are already in the router console FormHandler,
@ -1660,6 +1661,11 @@ public class WebMail extends HttpServlet
ctx); ctx);
isPOST = false; isPOST = false;
} }
} catch (IllegalStateException ise) {
// too big, can't get any parameters
sessionObject.error += ise.getMessage() + '\n';
isPOST = false;
}
} }
// This must be called to add the attachment before // This must be called to add the attachment before
@ -2027,6 +2033,19 @@ public class WebMail extends HttpServlet
sessionObject.error += "Internal error: Header line encoder not available."; sessionObject.error += "Internal error: Header line encoder not available.";
} }
long total = text.length();
boolean multipart = sessionObject.attachments != null && !sessionObject.attachments.isEmpty();
if (multipart) {
for(Attachment a : sessionObject.attachments) {
total += a.getSize();
}
}
if (total > SMTPClient.BINARY_MAX_SIZE) {
ok = false;
sessionObject.error += _t("Email is too large, max is {0}",
DataHelper.formatSize2(SMTPClient.BINARY_MAX_SIZE, false) + 'B') + '\n';
}
if( ok ) { if( ok ) {
StringBuilder body = new StringBuilder(1024); StringBuilder body = new StringBuilder(1024);
body.append( "From: " + from + "\r\n" ); body.append( "From: " + from + "\r\n" );
@ -2040,9 +2059,7 @@ public class WebMail extends HttpServlet
sessionObject.error += e.getMessage(); sessionObject.error += e.getMessage();
} }
String boundary = "_=" + I2PAppContext.getGlobalContext().random().nextLong(); String boundary = "_=" + I2PAppContext.getGlobalContext().random().nextLong();
boolean multipart = false; if (multipart) {
if( sessionObject.attachments != null && !sessionObject.attachments.isEmpty() ) {
multipart = true;
body.append( "\r\nMIME-Version: 1.0\r\nContent-type: multipart/mixed; boundary=\"" + boundary + "\"\r\n\r\n" ); body.append( "\r\nMIME-Version: 1.0\r\nContent-type: multipart/mixed; boundary=\"" + boundary + "\"\r\n\r\n" );
} }
else { else {

View File

@ -47,6 +47,20 @@ import net.i2p.data.DataHelper;
*/ */
public class SMTPClient { public class SMTPClient {
/**
* 31.84 MB
* smtp.postman.i2p as of 2017-12.
* @since 0.9.33
*/
public static final long DEFAULT_MAX_SIZE = 33388608;
/**
* About 23.25 MB.
* Base64 encodes 57 chars to 76 + \r\n on a line
* @since 0.9.33
*/
public static final long BINARY_MAX_SIZE = (long) ((DEFAULT_MAX_SIZE * 57.0d / 78) - 32*1024);
private Socket socket; private Socket socket;
public String error; public String error;
private String lastResponse; private String lastResponse;