forked from I2P_Developers/i2p.i2p
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:
@ -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;
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,7 +448,7 @@
|
|||||||
<!-- Add multipart config to servlets that need them -->
|
<!-- Add multipart config to servlets that need them -->
|
||||||
<property name="__match1" value="<servlet-class>net.i2p.router.web.jsp." />
|
<property name="__match1" value="<servlet-class>net.i2p.router.web.jsp." />
|
||||||
<property name="__match2" value="_jsp</servlet-class>" />
|
<property name="__match2" value="_jsp</servlet-class>" />
|
||||||
<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="
|
<property name="__multipart" value="
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
Reference in New Issue
Block a user