Solr: form-urlencoded content length exceeds upload limit


The Problem:
Our Solr client application(.Net) received the following exception:
<lst name="error"><str name="msg">application/x-www-form-urlencoded content length (20971671 bytes) exceeds upload limit of 2048 KB</str><int name="code">400</int></lst>

From the error message, seems the exception is thrown from Solr code. Search "exceeds upload limit of" in Solr code, it takes me to org.apache.solr.servlet.SolrRequestParsers.parseFormDataContent.
final long maxLength = ((long) uploadLimitKB) * 1024L;
if (totalLength > maxLength) {
	throw new SolrException(ErrorCode.BAD_REQUEST, "application/x-www-form-urlencoded content length (" +
		totalLength + " bytes) exceeds upload limit of " + uploadLimitKB + " KB");
}
Follow its call hierarchy, it finally takes me to org.apache.solr.servlet.SolrRequestParsers.SolrRequestParsers(Config)
public SolrRequestParsers( Config globalConfig ) {
  final int multipartUploadLimitKB, formUploadLimitKB;
	multipartUploadLimitKB = globalConfig.getInt( 
			"requestDispatcher/requestParsers/@multipartUploadLimitInKB", 2048 );
	
	formUploadLimitKB = globalConfig.getInt( 
			"requestDispatcher/requestParsers/@formdataUploadLimitInKB", 2048 );
  init(multipartUploadLimitKB, formUploadLimitKB);
}

Now it's obvious that Solr read parameter from requestDispatcher/requestParsers/@formdataUploadLimitInKB, if not set, will use use its default value: 2048KB: max size of form post body is 2048*1024 length.
The Solution The fix is to configure the formdataUploadLimitInKB, make it bigger.
<requestParsers enableRemoteStreaming="true" 
			multipartUploadLimitInKB="2048000" formdataUploadLimitInKB="2048000"  />
Verify the Solution
Now, to prove the change fixed the issue, I need first reproduce the issue without the formdataUploadLimitInKB change.
	public void testSolrJForm() throws IOException {
		CloseableHttpClient httpClient = HttpClientBuilder.create().build();

		HttpPost post = createUrlEncodePost();
		CloseableHttpResponse rsp = httpClient.execute(post);
		try {
			System.out.println(rsp.getStatusLine().getStatusCode());
			String rspStr = EntityUtils.toString(rsp.getEntity());
			System.out.println(rspStr);
		} finally {
			post.releaseConnection();
			rsp.close();
			httpClient.close();
		}
	}

	public HttpPost createUrlEncodePost() throws UnsupportedEncodingException {
		HttpPost post = new HttpPost(
				"http://localhost:8080/solr/update?commit=true");
		post.setHeader("Content-type", "application/x-www-form-urlencoded");
		String str = createBigString();
		StringBuilder xmlSb = new StringBuilder();
		xmlSb.append(
				"<add><doc><field name=\"contentid\">100</field><field name=\"content\">")
				.append(str).append("</field></doc></add>");

		List<NameValuePair> nameValuePairs = Lists.newArrayList();
		nameValuePairs.add(new BasicNameValuePair("stream.body", xmlSb
				.toString()));
		HttpEntity entity = new UrlEncodedFormEntity(nameValuePairs);
		post.setEntity(entity);
		return post;
	}

	public String createBigString() {
		char[] chars = new char[2048 * 1024 * 10];
		Arrays.fill(chars, 'a');
		String str = new String(chars);
		return str;
	}
It receives exception as expected.

Now make formdataUploadLimitInKB bigger in solrconfig.xml, restart solr server, rerun the test. 
Now it successfully upload the big SolrDocuemnt into Solr.

Now the problem solved.

Client application uses form-urlencoded to send solr xml doc, in post body, the key is stream.body, the value is the xml. 

This is kind of weird, we should set Content-type as application/xml and send the XML as http post body like below:
	public HttpPost createApllicationXMLPost()
			throws UnsupportedEncodingException {
		HttpPost post = new HttpPost(
				"http://localhost:8080/solr/update?commit=true");
		post.setHeader("Content-type", "application/xml");
		String str = createBigString();

		StringBuilder xmlSb = new StringBuilder();
		xmlSb.append(
				"<add><doc><field name=\"contentid\">100</field><field name=\"content\">")
				.append(str).append("</field></doc></add>");

		StringEntity entity = new StringEntity(xmlSb.toString());
		entity.setContentEncoding("UTF-8");
		post.setEntity(entity);

		return post;
	}

Labels

adsense (5) Algorithm (69) Algorithm Series (35) Android (7) ANT (6) bat (8) Big Data (7) Blogger (14) Bugs (6) Cache (5) Chrome (19) Code Example (29) Code Quality (7) Coding Skills (5) Database (7) Debug (16) Design (5) Dev Tips (63) Eclipse (32) Git (5) Google (33) Guava (7) How to (9) Http Client (8) IDE (7) Interview (88) J2EE (13) J2SE (49) Java (186) JavaScript (27) JSON (7) Learning code (9) Lesson Learned (6) Linux (26) Lucene-Solr (112) Mac (10) Maven (8) Network (9) Nutch2 (18) Performance (9) PowerShell (11) Problem Solving (11) Programmer Skills (6) regex (5) Scala (6) Security (9) Soft Skills (38) Spring (22) System Design (11) Testing (7) Text Mining (14) Tips (17) Tools (24) Troubleshooting (29) UIMA (9) Web Development (19) Windows (21) xml (5)