Skip to content

Commit bb5100d

Browse files
author
zhourenjian
committed
Supports Simple RPC in HTTP GET method
1 parent bff4831 commit bb5100d

File tree

3 files changed

+183
-97
lines changed

3 files changed

+183
-97
lines changed

sources/net.sf.j2s.ajax/ajaxrpc/net/sf/j2s/ajax/SimpleRPCHttpServlet.java

Lines changed: 148 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.PrintWriter;
2020
import java.lang.reflect.Constructor;
2121
import java.lang.reflect.InvocationTargetException;
22+
import java.net.URLDecoder;
2223
import java.util.Date;
2324
import java.util.Enumeration;
2425
import java.util.HashSet;
@@ -273,104 +274,39 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
273274
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
274275
throws ServletException, IOException {
275276
String request = req.getQueryString();
277+
// a quick check!
278+
if (request == null || request.length() < 4) {
279+
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
280+
return;
281+
}
282+
283+
boolean isScriptReuest = false;
284+
String requestID = null;
276285
/*
277286
* may be start with "jz[n|p|c|z]=", normal request may start with
278-
* "WLL100" or other tokens but charAt(3) should never be '='.
287+
* raw "WLL100" or other tokens but charAt(3) should never be '='.
279288
*/
280-
boolean isScriptRequest = request.charAt(3) == '=';
281-
282-
boolean supportScriptRequest = supportXSSRequest();
283-
284-
String nameID = null;
285-
if (supportScriptRequest) {
286-
HttpSession ses = req.getSession(false);
287-
if (ses != null) { // try to clean expired request!
288-
Enumeration attrNames = ses.getAttributeNames();
289-
while (attrNames.hasMoreElements()) {
290-
String name = (String) attrNames.nextElement();
291-
if (name.startsWith("jzt")) {
292-
Date dt = (Date) ses.getAttribute(name);
293-
if (new Date().getTime() - dt.getTime() > maxXSSRequestLatency()) {
294-
ses.removeAttribute(name);
295-
ses.removeAttribute("jzn" + name.substring(3));
296-
}
297-
}
298-
}
289+
if (request.charAt(3) == '=') { // simplerpc?jzn=604107&jzp=1&jzc=1&jzz=WLL100...
290+
request = req.getParameter("jzz"); // jzz without jzn is considered as XHR requests!
291+
if (request == null || request.trim().length() == 0) {
292+
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
293+
return;
299294
}
300-
if (isScriptRequest) { // simplerpc?jzn=604107&jzp=1&jzc=1&jzz=WLL100...
301-
nameID = req.getParameter("jzn");
302-
String count = req.getParameter("jzp");
303-
String current = req.getParameter("jzc");
304-
String content = req.getParameter("jzz");
305-
if (nameID == null || !nameID.matches("\\d{6,}")
306-
|| count == null || !count.matches("[1-9]\\d{0,2}")
307-
|| current == null || !current.matches("[1-9]\\d{0,2}")
308-
|| content == null || content.trim().length() == 0) {
309-
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
295+
296+
requestID = req.getParameter("jzn");
297+
if (requestID != null && requestID.length() != 0) {
298+
isScriptReuest = true;
299+
300+
// when jzn is defined, it's considered as a script request!
301+
request = prepareScriptRequest(req, resp, requestID, request);
302+
if (request == null) { // already send out reponses
310303
return;
311304
}
312-
int partsCount = Integer.parseInt(count);
313-
int curPart = Integer.parseInt(current);
314-
if (curPart > partsCount) {
315-
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
316-
return;
317-
}
318-
if (partsCount > maxXSSRequestParts()) {
319-
resp.setContentType("text/javascript");
320-
//resp.setCharacterEncoding("utf-8");
321-
resp.getWriter().write("net.sf.j2s.ajax.SimpleRPCRequest" +
322-
".xssNotify(\"" + nameID + "\", \"exceedrequestlimit\");");
323-
return;
324-
}
325-
if (partsCount != 1) {
326-
HttpSession session = req.getSession();
327-
String attrName = "jzn" + nameID;
328-
String attrTime = "jzt" + nameID;
329-
Object attr = session.getAttribute(attrName);
330-
String[] parts = null;
331-
if (attr == null) {
332-
parts = new String[partsCount];
333-
session.setAttribute(attrName, parts);
334-
session.setAttribute(attrTime, new Date());
335-
} else { // attr instanceof String[]
336-
parts = (String []) attr;
337-
if (partsCount != parts.length) {
338-
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
339-
return;
340-
}
341-
}
342-
parts[curPart - 1] = content;
343-
for (int i = 0; i < parts.length; i++) {
344-
if (parts[i] == null) {
345-
resp.setContentType("text/javascript");
346-
//resp.setCharacterEncoding("utf-8");
347-
resp.getWriter().write("net.sf.j2s.ajax.SimpleRPCRequest" +
348-
".xssNotify(\"" + nameID + "\", \"continue\");");
349-
return;
350-
}
351-
}
352-
synchronized (session) {
353-
session.removeAttribute(attrName);
354-
session.removeAttribute(attrTime);
355-
}
356-
StringBuffer buf = new StringBuffer();
357-
for (int i = 0; i < parts.length; i++) {
358-
buf.append(parts[i]);
359-
parts[i] = null;
360-
}
361-
request = buf.toString();
362-
} else { // bad request !
363-
request = content;
364-
}
365305
}
366-
} else if (isScriptRequest) {
367-
resp.setContentType("text/javascript");
368-
//resp.setCharacterEncoding("utf-8");
369-
nameID = req.getParameter("jzn");
370-
resp.getWriter().write("net.sf.j2s.ajax.SimpleRPCRequest" +
371-
".xssNotify(\"" + nameID + "\", \"unsupported\");");
372-
return;
306+
} else { // ?WLL100net.sf....%23...
307+
request = URLDecoder.decode(request, "UTF-8");
373308
}
309+
374310
SimpleRPCRunnable runnable = getRunnableByRequest(request);
375311
if (runnable == null) {
376312
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
@@ -379,23 +315,138 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
379315
runnable.deserialize(request);
380316
runnable.ajaxRun();
381317
String serialize = runnable.serialize();
382-
if (!isScriptRequest) {
383-
resp.setContentType("text/plain");
384-
//resp.setCharacterEncoding("utf-8");
385-
PrintWriter writer = resp.getWriter();
386-
writer.write(serialize);
387-
} else {
318+
319+
if (isScriptReuest) { // cross site script response
388320
resp.setContentType("text/javascript");
389321
//resp.setCharacterEncoding("utf-8");
390322
PrintWriter writer = resp.getWriter();
391323
writer.write("net.sf.j2s.ajax.SimpleRPCRequest.xssNotify(");
392-
writer.write("\"" + nameID + "\", \"");
324+
writer.write("\"" + requestID + "\", \"");
393325
writer.write(serialize.replaceAll("\r", "\\r")
394326
.replaceAll("\n", "\\n")
395327
.replaceAll("\"", "\\\""));
396328
writer.write("\");");
329+
return;
330+
}
331+
332+
// normal text response
333+
resp.setContentType("text/plain");
334+
//resp.setCharacterEncoding("utf-8");
335+
PrintWriter writer = resp.getWriter();
336+
writer.write(serialize);
337+
}
338+
339+
private String prepareScriptRequest(HttpServletRequest req, HttpServletResponse resp,
340+
String scriptRequestID, String request) throws IOException {
341+
342+
// check request id: must be 6 digitals
343+
if (!scriptRequestID.matches("\\d{6,}")) {
344+
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
345+
return null;
346+
}
347+
348+
// make sure that servlet support cross site script request
349+
if (!supportXSSRequest()) {
350+
resp.setContentType("text/javascript");
351+
//resp.setCharacterEncoding("utf-8");
352+
resp.getWriter().write("net.sf.j2s.ajax.SimpleRPCRequest" +
353+
".xssNotify(\"" + scriptRequestID + "\", \"unsupported\");");
354+
return null;
355+
}
356+
357+
// check script request counts
358+
String count = req.getParameter("jzp");
359+
if (count == null || !count.matches("[1-9]\\d{0,2}")) {
360+
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
361+
return null;
362+
}
363+
int partsCount = Integer.parseInt(count);
364+
if (partsCount == 1) {
365+
return request; // can be return directly
366+
}
367+
368+
// check curent request index
369+
String current = req.getParameter("jzc");
370+
if (current == null || !current.matches("[1-9]\\d{0,2}")) {
371+
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
372+
return null;
373+
}
374+
int curPart = Integer.parseInt(current);
375+
if (partsCount < 1 || curPart > partsCount) {
376+
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
377+
return null;
378+
}
379+
380+
// check whether servlet can deal the requests
381+
if (partsCount > maxXSSRequestParts()) {
382+
resp.setContentType("text/javascript");
383+
//resp.setCharacterEncoding("utf-8");
384+
resp.getWriter().write("net.sf.j2s.ajax.SimpleRPCRequest" +
385+
".xssNotify(\"" + scriptRequestID + "\", \"exceedrequestlimit\");");
386+
return null;
387+
}
388+
389+
// clean dead session bodies
390+
cleanSession(req);
391+
392+
// store request in session before the request is completed
393+
HttpSession session = req.getSession();
394+
String attrName = "jzn" + scriptRequestID;
395+
String attrTime = "jzt" + scriptRequestID;
396+
Object attr = session.getAttribute(attrName);
397+
String[] parts = null;
398+
if (attr == null) {
399+
parts = new String[partsCount];
400+
session.setAttribute(attrName, parts);
401+
session.setAttribute(attrTime, new Date());
402+
} else { // attr instanceof String[]
403+
parts = (String []) attr;
404+
if (partsCount != parts.length) {
405+
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
406+
return null;
407+
}
408+
}
409+
parts[curPart - 1] = request;
410+
for (int i = 0; i < parts.length; i++) {
411+
if (parts[i] == null) {
412+
// not completed yet! just response and wait next request.
413+
414+
resp.setContentType("text/javascript");
415+
//resp.setCharacterEncoding("utf-8");
416+
resp.getWriter().write("net.sf.j2s.ajax.SimpleRPCRequest" +
417+
".xssNotify(\"" + scriptRequestID + "\", \"continue\");");
418+
return null;
419+
}
397420
}
421+
422+
// request is completed. return the request
423+
synchronized (session) {
424+
session.removeAttribute(attrName);
425+
session.removeAttribute(attrTime);
426+
}
427+
StringBuffer buf = new StringBuffer();
428+
for (int i = 0; i < parts.length; i++) {
429+
buf.append(parts[i]);
430+
parts[i] = null;
431+
}
432+
return buf.toString();
398433
}
399434

435+
private void cleanSession(HttpServletRequest req) {
436+
HttpSession ses = req.getSession(false);
437+
if (ses != null) { // try to clean expired request!
438+
Enumeration attrNames = ses.getAttributeNames();
439+
while (attrNames.hasMoreElements()) {
440+
String name = (String) attrNames.nextElement();
441+
if (name.startsWith("jzt")) {
442+
Date dt = (Date) ses.getAttribute(name);
443+
if (new Date().getTime() - dt.getTime() > maxXSSRequestLatency()) {
444+
ses.removeAttribute(name);
445+
ses.removeAttribute("jzn" + name.substring(3));
446+
}
447+
}
448+
}
449+
}
450+
}
400451

401452
}

sources/net.sf.j2s.ajax/ajaxrpc/net/sf/j2s/ajax/SimpleRPCRequest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
package net.sf.j2s.ajax;
1515

16+
import java.io.UnsupportedEncodingException;
17+
import java.net.URLEncoder;
18+
1619
/**
1720
* @author josson smith
1821
*
@@ -76,6 +79,21 @@ private static void ajaxRequest(final SimpleRPCRunnable runnable) {
7679
if (checkXSS(url, serialize, runnable)) {
7780
return;
7881
}
82+
if ("get".equals(method.toLowerCase())) {
83+
try {
84+
String query = URLEncoder.encode(serialize, "UTF-8");
85+
if (url.indexOf('?') != -1) {
86+
/* should not come to this branch! */
87+
url += "&jzz=" + query;
88+
} else {
89+
url += "?" + query;
90+
}
91+
serialize = null;
92+
} catch (UnsupportedEncodingException e) {
93+
// should never throws such exception!
94+
//e.printStackTrace();
95+
}
96+
}
7997
final HttpRequest request = new HttpRequest();
8098
request.open(method, url, true);
8199
request.registerOnReadyStateChange(new XHRCallbackAdapter() {

sources/net.sf.j2s.ajax/ajaxrpc/net/sf/j2s/ajax/SimpleRPCSWTRequest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
package net.sf.j2s.ajax;
1515

16+
import java.io.UnsupportedEncodingException;
17+
import java.net.URLEncoder;
1618
import org.eclipse.swt.widgets.Display;
1719

1820
/**
@@ -46,6 +48,21 @@ private static void swtAJAXRequest(final SimpleRPCRunnable runnable) {
4648
if (checkXSS(url, serialize, runnable)) {
4749
return;
4850
}
51+
if ("get".equals(method.toLowerCase())) {
52+
try {
53+
String query = URLEncoder.encode(serialize, "UTF-8");
54+
if (url.indexOf('?') != -1) {
55+
/* should not come to this branch! */
56+
url += "&jzz=" + query;
57+
} else {
58+
url += "?" + query;
59+
}
60+
serialize = null;
61+
} catch (UnsupportedEncodingException e) {
62+
// should never throws such exception!
63+
//e.printStackTrace();
64+
}
65+
}
4966
final HttpRequest request = new HttpRequest();
5067
request.open(method, url, true);
5168
request.registerOnReadyStateChange(new XHRCallbackSWTAdapter() {

0 commit comments

Comments
 (0)